diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-volgen.c')
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 8132 |
1 files changed, 6125 insertions, 2007 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 782170c9a3a..8d6fb5e0fac 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -1,2636 +1,6754 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is GF_FREE software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif +#include <fnmatch.h> +#include <sys/wait.h> +#include <dlfcn.h> +#include <utime.h> -#include "xlator.h" -#include "protocol-common.h" +#include <glusterfs/xlator.h> #include "glusterd.h" -#include "defaults.h" -#include "list.h" -#include "dict.h" -#include "compat.h" -#include "compat-errno.h" -#include "glusterd-sm.h" -#include "glusterd-op-sm.h" -#include "cli1.h" +#include <glusterfs/defaults.h> +#include <glusterfs/syscall.h> +#include <glusterfs/logging.h> +#include <glusterfs/dict.h> +#include <glusterfs/graph-utils.h> +#include <glusterfs/common-utils.h> +#include "glusterd-store.h" +#include "glusterd-hooks.h" +#include <glusterfs/trie.h> #include "glusterd-mem-types.h" +#include "cli1-xdr.h" #include "glusterd-volgen.h" +#include "glusterd-geo-rep.h" #include "glusterd-utils.h" +#include "glusterd-messages.h" +#include <glusterfs/run.h> +#include <glusterfs/options.h> +#include "glusterd-snapshot-utils.h" +#include "glusterd-svc-mgmt.h" +#include "glusterd-svc-helper.h" +#include "glusterd-snapd-svc-helper.h" +#include "glusterd-shd-svc-helper.h" +#include "glusterd-gfproxyd-svc-helper.h" + +struct gd_validate_reconf_opts { + dict_t *options; + char **op_errstr; +}; + +extern struct volopt_map_entry glusterd_volopt_map[]; + +#define RPC_SET_OPT(XL, CLI_OPT, XLATOR_OPT, ERROR_CMD) \ + do { \ + char *_value = NULL; \ + \ + if (dict_get_str_sizen(set_dict, CLI_OPT, &_value) == 0) { \ + if (xlator_set_fixed_option(XL, "transport.socket." XLATOR_OPT, \ + _value) != 0) { \ + gf_msg("glusterd", GF_LOG_WARNING, errno, \ + GD_MSG_XLATOR_SET_OPT_FAIL, \ + "failed to set " XLATOR_OPT); \ + ERROR_CMD; \ + } \ + } \ + } while (0 /* CONSTCOND */) -int -set_xlator_option (dict_t *dict, char *key, - char *value) -{ - int ret = 0; - char *str = NULL; +static int +volgen_graph_build_clients(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param); - str = GF_CALLOC (1, strlen (value) + 1, - gf_gld_mt_char); +static int +build_client_graph(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict); - if (!str) - return -1; +/********************************************* + * + * xlator generation / graph manipulation API + * + *********************************************/ - strncpy (str, value, strlen (value)); +static void +set_graph_errstr(volgen_graph_t *graph, const char *str) +{ + if (!graph->errstr) + return; - ret = dict_set_dynstr (dict, key, str); + *graph->errstr = gf_strdup(str); +} - return ret; +static xlator_t * +xlator_instantiate_va(const char *type, const char *format, va_list arg) +{ + xlator_t *xl = NULL; + char *volname = NULL; + int ret = 0; + xlator_t *this = THIS; + GF_ASSERT(this); + + ret = gf_vasprintf(&volname, format, arg); + if (ret < 0) { + volname = NULL; + + goto error; + } + + xl = GF_CALLOC(1, sizeof(*xl), gf_common_mt_xlator_t); + if (!xl) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_NO_MEMORY, NULL); + goto error; + } + ret = xlator_set_type_virtual(xl, type); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_XLATOR_SET_OPT_FAIL, + NULL); + goto error; + } + xl->options = dict_new(); + if (!xl->options) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + goto error; + } + xl->name = volname; + CDS_INIT_LIST_HEAD(&xl->volume_options); + + xl->ctx = THIS->ctx; + + return xl; + +error: + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_XLATOR_CREATE_FAIL, "Type=%s", + type, NULL); + GF_FREE(volname); + if (xl) + xlator_destroy(xl); + + return NULL; } -static int32_t -set_default_options (dict_t *dict, char *volname) +static int +volgen_xlator_link(xlator_t *pxl, xlator_t *cxl) { - int ret = -1; + int ret = 0; - ret = dict_set_str (dict, "volname", - volname); - if (ret) - goto out; + ret = glusterfs_xlator_link(pxl, cxl); + if (ret == -1) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Out of memory, cannot link xlators %s <- %s", pxl->name, + cxl->name); + } - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_ODIRECT, - "on"); - if (ret) - goto out; + return ret; +} - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_STATFSSIZE, - "on"); - if (ret) - goto out; +static int +volgen_graph_link(volgen_graph_t *graph, xlator_t *xl) +{ + int ret = 0; - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_MANDATTR, - "on"); - if (ret) - goto out; + /* no need to care about graph->top here */ + if (graph->graph.first) + ret = volgen_xlator_link(xl, graph->graph.first); + if (ret == -1) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_GRAPH_ENTRY_ADD_FAIL, + "failed to add graph entry %s", xl->name); - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_SPANDEVICES, - "1"); - if (ret) - goto out; + return -1; + } - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_BCKUNLINK, - "on"); - if (ret) - goto out; + return 0; +} - ret = set_xlator_option (dict, VOLGEN_LOCKS_OPTION_TRACE, - "on"); - if (ret) - goto out; +static xlator_t * +volgen_graph_add_as(volgen_graph_t *graph, const char *type, const char *format, + ...) +{ + va_list arg; + xlator_t *xl = NULL; - ret = set_xlator_option (dict, VOLGEN_LOCKS_OPTION_MAND, - "on"); - if (ret) - goto out; + va_start(arg, format); + xl = xlator_instantiate_va(type, format, arg); + va_end(arg); - ret = set_xlator_option (dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - "tcp"); - if (ret) - goto out; + if (!xl) + return NULL; - ret = set_xlator_option (dict, VOLGEN_CLIENT_OPTION_NODELAY, - "on"); - if (ret) - goto out; + if (volgen_graph_link(graph, xl)) { + xlator_destroy(xl); - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_THREADCOUNT, - "16"); - if (ret) - goto out; + return NULL; + } else + glusterfs_graph_set_first(&graph->graph, xl); - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_AUTOSCALING, - "on"); - if (ret) - goto out; + return xl; +} - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_MINTHREADS, - "on"); - if (ret) - goto out; +static xlator_t * +volgen_graph_add_nolink(volgen_graph_t *graph, const char *type, + const char *format, ...) +{ + va_list arg; + xlator_t *xl = NULL; - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_MAXTHREADS, - "on"); - if (ret) - goto out; + va_start(arg, format); + xl = xlator_instantiate_va(type, format, arg); + va_end(arg); - ret = set_xlator_option (dict, VOLGEN_SERVER_OPTION_TRANSTYPE, - "tcp"); - if (ret) - goto out; + if (!xl) + return NULL; - ret = set_xlator_option (dict, VOLGEN_SERVER_OPTION_NODELAY, - "on"); - if (ret) - goto out; + glusterfs_graph_set_first(&graph->graph, xl); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_READSUBVOL, - "on"); - if (ret) - goto out; + return xl; +} - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_FAVCHILD, - "on"); - if (ret) - goto out; +static xlator_t * +volgen_graph_add(volgen_graph_t *graph, char *type, char *volname) +{ + char *shorttype = NULL; - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_BCKSHCOUNT, - "on"); - if (ret) - goto out; + shorttype = strrchr(type, '/'); + GF_ASSERT(shorttype); + shorttype++; + GF_ASSERT(*shorttype); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_DATASH, - "on"); - if (ret) - goto out; + return volgen_graph_add_as(graph, type, "%s-%s", volname, shorttype); +} - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_DATASHALGO, - "on"); - if (ret) - goto out; +#define xlator_set_fixed_option(xl, key, value) \ + xlator_set_option(xl, key, SLEN(key), value) - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_SHWINDOWSIZE, - "on"); - if (ret) - goto out; +/* XXX Seems there is no such generic routine? + * Maybe should put to xlator.c ?? + */ +static int +xlator_set_option(xlator_t *xl, char *key, const int keylen, char *value) +{ + char *dval = gf_strdup(value); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_METASH, - "on"); - if (ret) - goto out; + if (!dval) { + gf_msg("glusterd", GF_LOG_ERROR, errno, GD_MSG_NO_MEMORY, + "failed to set xlator opt: %s[%s] = %s", xl->name, key, value); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_ENTRYSH, - "on"); - if (ret) - goto out; + return -1; + } - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_DATACHANGELOG, - "on"); - if (ret) - goto out; + return dict_set_dynstrn(xl->options, key, keylen, dval); +} - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_METADATACHANGELOG, - "on"); - if (ret) - goto out; +#define xlator_get_fixed_option(xl, key, value) \ + xlator_get_option(xl, key, SLEN(key), value) - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_ENTRYCHANGELOG, - "on"); - if (ret) - goto out; +static int +xlator_get_option(xlator_t *xl, char *key, const int keylen, char **value) +{ + GF_ASSERT(xl); + return dict_get_strn(xl->options, key, keylen, value); +} - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_STRICTREADDIR, - "on"); - if (ret) - goto out; +static xlator_t * +first_of(volgen_graph_t *graph) +{ + return (xlator_t *)graph->graph.first; +} - ret = set_xlator_option (dict, VOLGEN_STRIPE_OPTION_BLOCKSIZE, - "on"); - if (ret) - goto out; +/************************** + * + * Trie glue + * + *************************/ - ret = set_xlator_option (dict, VOLGEN_STRIPE_OPTION_USEXATTR, - "on"); +static int +volopt_selector(int lvl, char **patt, void *param, + int (*optcbk)(char *word, void *param)) +{ + struct volopt_map_entry *vme = NULL; + char *w = NULL; + int i = 0; + int len = 0; + int ret = 0; + char *dot = NULL; + + for (vme = glusterd_volopt_map; vme->key; vme++) { + w = vme->key; + + for (i = 0; i < lvl; i++) { + if (patt[i]) { + w = strtail(w, patt[i]); + GF_ASSERT(!w || *w); + if (!w || *w != '.') + goto next; + } else { + w = strchr(w, '.'); + GF_ASSERT(w); + } + w++; + } + + dot = strchr(w, '.'); + if (dot) { + len = dot - w; + w = gf_strdup(w); + if (!w) + return -1; + w[len] = '\0'; + } + ret = optcbk(w, param); + if (dot) + GF_FREE(w); if (ret) - goto out; + return -1; + next: + continue; + } - ret = set_xlator_option (dict, VOLGEN_DHT_OPTION_LOOKUPUNHASH, - "on"); - if (ret) - goto out; + return 0; +} - ret = set_xlator_option (dict, VOLGEN_DHT_OPTION_MINFREEDISK, - "on"); - if (ret) - goto out; +static int +volopt_trie_cbk(char *word, void *param) +{ + return trie_add((trie_t *)param, word); +} - ret = set_xlator_option (dict, VOLGEN_DHT_OPTION_UNHASHSTICKY, - "on"); - if (ret) - goto out; +static int +process_nodevec(struct trienodevec *nodevec, char **outputhint, char *inputhint) +{ + int ret = 0; + char *hint1 = NULL; + char *hint2 = NULL; + char *hintinfx = ""; + trienode_t **nodes = nodevec->nodes; + + if (!nodes[0]) { + *outputhint = NULL; + return 0; + } - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_FLUSHBEHIND, - "on"); - if (ret) - goto out; +#if 0 + /* Limit as in git */ + if (trienode_get_dist (nodes[0]) >= 6) { + *outputhint = NULL; + return 0; + } +#endif - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_CACHESIZE, - "on"); - if (ret) - goto out; + if (trienode_get_word(nodes[0], &hint1)) + return -1; - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_DISABLENBYTES, - "on"); - if (ret) - goto out; + if (nodevec->cnt < 2 || !nodes[1]) { + *outputhint = hint1; + return 0; + } - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_OSYNC, - "on"); - if (ret) - goto out; + if (trienode_get_word(nodes[1], &hint2)) { + GF_FREE(hint1); + return -1; + } - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_TRICKLINGWRITES, - "on"); - if (ret) - goto out; + if (inputhint) + hintinfx = inputhint; + ret = gf_asprintf(outputhint, "%s or %s%s", hint1, hintinfx, hint2); + if (ret > 0) + ret = 0; + if (hint1) + GF_FREE(hint1); + if (hint2) + GF_FREE(hint2); + return ret; +} - ret = set_xlator_option (dict, VOLGEN_RA_OPTION_ATIME, - "on"); - if (ret) - goto out; +static int +volopt_trie_section(int lvl, char **patt, char *word, char **outputhint, + char *inputhint, int hints) +{ + trienode_t *nodes[] = {NULL, NULL}; + struct trienodevec nodevec = {nodes, 2}; + trie_t *trie = NULL; + int ret = 0; - ret = set_xlator_option (dict, VOLGEN_RA_OPTION_PAGECOUNT, - "on"); - if (ret) - goto out; + trie = trie_new(); + if (!trie) + return -1; - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_PRIORITY, - "on"); - if (ret) - goto out; + if (volopt_selector(lvl, patt, trie, &volopt_trie_cbk)) { + trie_destroy(trie); - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_TIMEOUT, - "on"); - if (ret) - goto out; + return -1; + } - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_CACHESIZE, - "on"); - if (ret) - goto out; + GF_ASSERT(hints <= 2); + nodevec.cnt = hints; + ret = trie_measure_vec(trie, word, &nodevec); + if (!ret && nodevec.nodes[0]) + ret = process_nodevec(&nodevec, outputhint, inputhint); - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_MINFILESIZE, - "on"); - if (ret) - goto out; + trie_destroy(trie); - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_MAXFILESIZE, - "on"); - if (ret) - goto out; + return ret; +} - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_PRIORITY, - "on"); - if (ret) - goto out; +static int +volopt_trie(char *key, char **hint) +{ + char *patt[] = {NULL}; + char *fullhint = NULL; + char *inputhint = NULL; + char *dot = NULL; + char *dom = NULL; + int len = 0; + int ret = 0; + + *hint = NULL; + + dot = strchr(key, '.'); + if (!dot) + return volopt_trie_section(1, patt, key, hint, inputhint, 2); + + len = dot - key; + dom = gf_strdup(key); + if (!dom) + return -1; + dom[len] = '\0'; + + ret = volopt_trie_section(0, NULL, dom, patt, inputhint, 1); + GF_FREE(dom); + if (ret) { + patt[0] = NULL; + goto out; + } + if (!patt[0]) + goto out; + + inputhint = "..."; + ret = volopt_trie_section(1, patt, dot + 1, hint, inputhint, 2); + if (ret) + goto out; + if (*hint) { + ret = gf_asprintf(&fullhint, "%s.%s", patt[0], *hint); + GF_FREE(*hint); + if (ret >= 0) { + ret = 0; + *hint = fullhint; + } + } - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_TIMEOUT, - "on"); - if (ret) - goto out; +out: + GF_FREE(patt[0]); + if (ret) + *hint = NULL; - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_CACHESIZE, - "on"); - if (ret) - goto out; + return ret; +} - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_MAXFILESIZE, - "on"); - if (ret) - goto out; +/************************** + * + * Volume generation engine + * + **************************/ + +typedef int (*volgen_opthandler_t)(volgen_graph_t *graph, + struct volopt_map_entry *vme, void *param); + +struct opthandler_data { + volgen_graph_t *graph; + volgen_opthandler_t handler; + struct volopt_map_entry *vme; + gf_boolean_t found; + gf_boolean_t data_t_fake; + int rv; + char *volname; + void *param; +}; + +static void +process_option(char *key, data_t *value, void *param) +{ + struct opthandler_data *odt = param; + struct volopt_map_entry vme = { + 0, + }; + + if (odt->rv) + return; + odt->found = _gf_true; + + vme.key = key; + vme.voltype = odt->vme->voltype; + vme.option = odt->vme->option; + vme.op_version = odt->vme->op_version; + + if (!vme.option) { + vme.option = strrchr(key, '.'); + if (vme.option) + vme.option++; + else + vme.option = key; + } + if (odt->data_t_fake) + vme.value = (char *)value; + else + vme.value = value->data; + + odt->rv = odt->handler(odt->graph, &vme, odt->param); + return; +} - ret = set_xlator_option (dict, VOLGEN_IOS_OPTION_DUMP_FD_STATS, - "no"); - if (ret) - goto out; +static int +volgen_graph_set_options_generic(volgen_graph_t *graph, dict_t *dict, + void *param, volgen_opthandler_t handler) +{ + struct volopt_map_entry *vme = NULL; + struct opthandler_data odt = { + 0, + }; + data_t *data = NULL; + int keylen; + + odt.graph = graph; + odt.handler = handler; + odt.param = param; + (void)data; + + for (vme = glusterd_volopt_map; vme->key; vme++) { + keylen = strlen(vme->key); + if (keylen == SLEN("performance.client-io-threads") && + !strcmp(vme->key, "performance.client-io-threads") && + dict_get_str_boolean(dict, "skip-CLIOT", _gf_false) == _gf_true) { + continue; + } + + odt.vme = vme; + odt.found = _gf_false; + odt.data_t_fake = _gf_false; + data = dict_getn(dict, vme->key, keylen); + if (data) + process_option(vme->key, data, &odt); + if (odt.rv) + return odt.rv; + + if (odt.found) + continue; + + /* check for default value */ + + if (vme->value) { + /* stupid hack to be able to reuse dict iterator + * in this context + */ + odt.data_t_fake = _gf_true; + process_option(vme->key, (data_t *)vme->value, &odt); + if (odt.rv) + return odt.rv; + } + } + + return 0; +} - ret = set_xlator_option (dict, VOLGEN_IOS_OPTION_MEASURE_LATENCY, - "no"); +static int +no_filter_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + xlator_t *trav; + int ret = 0; + + for (trav = first_of(graph); trav; trav = trav->next) { + if (strcmp(trav->type, vme->voltype) != 0) + continue; + if (strcmp(vme->option, "ta-remote-port") == 0) { + if (strstr(trav->name, "-ta-") != NULL) { + ret = xlator_set_option(trav, "remote-port", + strlen(vme->option), vme->value); + } + continue; + } + ret = xlator_set_option(trav, vme->option, strlen(vme->option), + vme->value); if (ret) - goto out; + break; + } + return ret; +} - ret = 0; +static int +basic_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + int ret = 0; + + if (vme->option[0] == '!') + goto out; + ret = no_filter_option_handler(graph, vme, param); out: - return ret; + return ret; } -int32_t -glusterd_default_xlator_options (glusterd_volinfo_t *volinfo) +static int +volgen_graph_set_options(volgen_graph_t *graph, dict_t *dict) { - int ret = -1; + return volgen_graph_set_options_generic(graph, dict, NULL, + &basic_option_handler); +} - volinfo->dict = dict_new (); - if (!volinfo->dict) { - ret = -1; - goto out; - } +static int +optget_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + struct volopt_map_entry *vme2 = param; - ret = set_default_options (volinfo->dict, - volinfo->volname); - if (ret) { - dict_unref (volinfo->dict); - goto out; - } + if (strcmp(vme->key, vme2->key) == 0) + vme2->value = vme->value; - ret = 0; + return 0; +} -out: - return ret; +/* This getter considers defaults also. */ +static int +volgen_dict_get(dict_t *dict, char *key, char **value) +{ + struct volopt_map_entry vme = { + 0, + }; + int ret = 0; + + vme.key = key; + ret = volgen_graph_set_options_generic(NULL, dict, &vme, + &optget_option_handler); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Out of memory"); + + return -1; + } + + *value = vme.value; + + return 0; } static int -__write_posix_xlator (FILE *file, dict_t *dict, - char *posix_directory) +option_complete(char *key, char **completion) { - char *volname = NULL; - char *opt_odirect = NULL; - char *opt_statfssize = NULL; - char *opt_mandattr = NULL; - char *opt_spandevices = NULL; - char *opt_bckunlink = NULL; - int ret = -1; + struct volopt_map_entry *vme = NULL; - const char *posix_str = "volume %s-%s\n" - " type storage/posix\n" - " option directory %s\n" - "# option o-direct %s\n" - "# option export-statfs-size %s\n" - "# option mandate-attribute %s\n" - "# option span-devices %s\n" - "# option background-unlink %s\n" - "end-volume\n\n"; + *completion = NULL; + for (vme = glusterd_volopt_map; vme->key; vme++) { + if (strcmp(strchr(vme->key, '.') + 1, key) != 0) + continue; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; + if (*completion && strcmp(*completion, vme->key) != 0) { + /* cancel on non-unique match */ + *completion = NULL; + + return 0; + } else + *completion = vme->key; + } + + if (*completion) { + /* For sake of unified API we want + * have the completion to be a to-be-freed + * string. + */ + *completion = gf_strdup(*completion); + return -!*completion; + } + + return 0; +} + +int +glusterd_volinfo_get(glusterd_volinfo_t *volinfo, char *key, char **value) +{ + return volgen_dict_get(volinfo->dict, key, value); +} + +int +glusterd_volinfo_get_boolean(glusterd_volinfo_t *volinfo, char *key) +{ + char *val = NULL; + gf_boolean_t enabled = _gf_false; + int ret = 0; + + ret = glusterd_volinfo_get(volinfo, key, &val); + if (ret) + return -1; + + if (val) + ret = gf_string2boolean(val, &enabled); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, + "value for %s option is not valid", key); + + return -1; + } + + return enabled; +} + +gf_boolean_t +glusterd_check_voloption_flags(char *key, int32_t flags) +{ + char *completion = NULL; + struct volopt_map_entry *vmep = NULL; + int ret = 0; + + COMPLETE_OPTION(key, completion, ret); + for (vmep = glusterd_volopt_map; vmep->key; vmep++) { + if (strcmp(vmep->key, key) == 0) { + if (vmep->flags & flags) + return _gf_true; + else + return _gf_false; } + } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_ODIRECT, - &opt_odirect); - if (ret) { - goto out; + return _gf_false; +} + +gf_boolean_t +glusterd_check_globaloption(char *key) +{ + char *completion = NULL; + struct volopt_map_entry *vmep = NULL; + int ret = 0; + + COMPLETE_OPTION(key, completion, ret); + for (vmep = glusterd_volopt_map; vmep->key; vmep++) { + if (strcmp(vmep->key, key) == 0) { + if ((vmep->type == GLOBAL_DOC) || (vmep->type == GLOBAL_NO_DOC)) + return _gf_true; + else + return _gf_false; } + } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_STATFSSIZE, - &opt_statfssize); - if (ret) { - goto out; + return _gf_false; +} + +gf_boolean_t +glusterd_check_localoption(char *key) +{ + char *completion = NULL; + struct volopt_map_entry *vmep = NULL; + int ret = 0; + + COMPLETE_OPTION(key, completion, ret); + for (vmep = glusterd_volopt_map; vmep->key; vmep++) { + if (strcmp(vmep->key, key) == 0) { + if ((vmep->type == DOC) || (vmep->type == NO_DOC)) + return _gf_true; + else + return _gf_false; } + } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_MANDATTR, - &opt_mandattr); - if (ret) { - goto out; + return _gf_false; +} + +int +glusterd_check_option_exists(char *key, char **completion) +{ + struct volopt_map_entry vme = { + 0, + }; + struct volopt_map_entry *vmep = NULL; + int ret = 0; + xlator_t *this = THIS; + + (void)vme; + (void)vmep; + + if (!strchr(key, '.')) { + if (completion) { + ret = option_complete(key, completion); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Out of memory"); + return -1; + } + + ret = !!*completion; + if (ret) + return ret; + else + goto trie; + } else + return 0; + } + + for (vmep = glusterd_volopt_map; vmep->key; vmep++) { + if (strcmp(vmep->key, key) == 0) { + ret = 1; + break; } + } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_SPANDEVICES, - &opt_spandevices); - if (ret) { + if (ret || !completion) + return ret; + +trie: + ret = volopt_trie(key, completion); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_ERROR_ENCOUNTERED, + "Some error occurred during keyword hinting"); + } + + return ret; +} + +int +glusterd_volopt_validate(glusterd_volinfo_t *volinfo, dict_t *dict, char *key, + char *value, char **op_errstr) +{ + struct volopt_map_entry *vme = NULL; + int ret = 0; + xlator_t *this = THIS; + + if (!dict || !key || !value) { + gf_msg_callingfn(this->name, GF_LOG_WARNING, EINVAL, + GD_MSG_INVALID_ENTRY, + "Invalid " + "Arguments (dict=%p, key=%s, value=%s)", + dict, key, value); + return -1; + } + + for (vme = &glusterd_volopt_map[0]; vme->key; vme++) { + if ((vme->validate_fn) && ((!strcmp(key, vme->key)) || + (!strcmp(key, strchr(vme->key, '.') + 1)))) { + if ((vme->type != GLOBAL_DOC && vme->type != GLOBAL_NO_DOC) && + !volinfo) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, + "%s is not" + " a global option", + vme->key); + ret = -1; + goto out; + } + ret = vme->validate_fn(volinfo, dict, key, value, op_errstr); + if (ret) goto out; + break; } + } +out: + return ret; +} + +char * +glusterd_get_trans_type_rb(gf_transport_type ttype) +{ + char *trans_type = NULL; + + switch (ttype) { + case GF_TRANSPORT_RDMA: + gf_asprintf(&trans_type, "rdma"); + break; + case GF_TRANSPORT_TCP: + case GF_TRANSPORT_BOTH_TCP_RDMA: + gf_asprintf(&trans_type, "tcp"); + break; + default: + gf_msg(THIS->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, + "Unknown " + "transport type"); + } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_BCKUNLINK, - &opt_bckunlink); + return trans_type; +} + +static int +_xl_link_children(xlator_t *parent, xlator_t *children, size_t child_count) +{ + xlator_t *trav = NULL; + size_t seek = 0; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (child_count == 0) + goto out; + seek = child_count; + for (trav = children; --seek; trav = trav->next) + ; + for (; child_count--; trav = trav->prev) { + ret = volgen_xlator_link(parent, trav); + gf_msg_debug(this->name, 0, "%s:%s", parent->name, trav->name); if (ret) { - goto out; + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_XLATOR_LINK_FAIL, + NULL); + goto out; } + } + ret = 0; +out: + return ret; +} - fprintf (file, posix_str, - volname, - "posix", - posix_directory, - opt_odirect, - opt_statfssize, - opt_mandattr, - opt_spandevices, - opt_bckunlink); +static int +volgen_graph_merge_sub(volgen_graph_t *dgraph, volgen_graph_t *sgraph, + size_t child_count) +{ + xlator_t *trav = NULL; + int ret = 0; - ret = 0; + GF_ASSERT(dgraph->graph.first); + + ret = _xl_link_children(first_of(dgraph), first_of(sgraph), child_count); + if (ret) + goto out; + + for (trav = first_of(dgraph); trav->next; trav = trav->next) + ; + + trav->next = first_of(sgraph); + trav->next->prev = trav; + dgraph->graph.xl_count += sgraph->graph.xl_count; out: - return ret; + return ret; +} + +static void +volgen_apply_filters(char *orig_volfile) +{ + DIR *filterdir = NULL; + struct dirent *entry = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + struct stat statbuf = { + 0, + }; + char filterpath[PATH_MAX] = { + 0, + }; + + filterdir = sys_opendir(FILTERDIR); + + if (!filterdir) + return; + + for (;;) { + errno = 0; + + entry = sys_readdir(filterdir, scratch); + + if (!entry || errno != 0) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_READ_ERROR, NULL); + break; + } + + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + /* + * d_type isn't guaranteed to be present/valid on all systems, + * so do an explicit stat instead. + */ + (void)snprintf(filterpath, sizeof(filterpath), "%s/%s", FILTERDIR, + entry->d_name); + + /* Deliberately use stat instead of lstat to allow symlinks. */ + if (sys_stat(filterpath, &statbuf) == -1) + continue; + + if (!S_ISREG(statbuf.st_mode)) + continue; + /* + * We could check the mode in statbuf directly, or just skip + * this entirely and check for EPERM after exec fails, but this + * is cleaner. + */ + if (sys_access(filterpath, X_OK) != 0) + continue; + + if (runcmd(filterpath, orig_volfile, NULL)) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_FILTER_RUN_FAILED, + "failed to run filter %s", entry->d_name); + } + } + + (void)sys_closedir(filterdir); } static int -__write_locks_xlator (FILE *file, dict_t *dict, - char *subvolume) +volgen_write_volfile(volgen_graph_t *graph, char *filename) { - char *volname = NULL; - char *opt_trace = NULL; - char *opt_mand = NULL; - int ret = -1; + char *ftmp = NULL; + FILE *f = NULL; + int fd = 0; + xlator_t *this = NULL; - const char *locks_str = "volume %s-%s\n" - " type features/locks\n" - "# option trace %s\n" - "# option mandatory %s\n" - " subvolumes %s\n" - "end-volume\n\n"; + this = THIS; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + if (gf_asprintf(&ftmp, "%s.tmp", filename) == -1) { + ftmp = NULL; + goto error; + } - ret = dict_get_str (dict, VOLGEN_LOCKS_OPTION_TRACE, - &opt_trace); - if (ret) { - goto out; - } + fd = sys_creat(ftmp, S_IRUSR | S_IWUSR); + if (fd < 0) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "file creation failed"); + goto error; + } - ret = dict_get_str (dict, VOLGEN_LOCKS_OPTION_MAND, - &opt_mand); - if (ret) { - goto out; - } + sys_close(fd); - fprintf (file, locks_str, - volname, - "locks", - opt_trace, - opt_mand, - subvolume); + f = fopen(ftmp, "w"); + if (!f) + goto error; - ret = 0; + if (glusterfs_graph_print_file(f, &graph->graph) == -1) + goto error; + + if (fclose(f) != 0) { + gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "fclose on the file %s " + "failed", + ftmp); + /* + * Even though fclose has failed here, we have to set f to NULL. + * Otherwise when the code path goes to error, there again we + * try to close it which might cause undefined behavior such as + * process crash. + */ + f = NULL; + goto error; + } + + f = NULL; + + if (sys_rename(ftmp, filename) == -1) + goto error; + + GF_FREE(ftmp); + + volgen_apply_filters(filename); + + return 0; + +error: + + GF_FREE(ftmp); + if (f) + fclose(f); + + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL, + "failed to create volfile %s", filename); + + return -1; +} + +static void +volgen_graph_free(volgen_graph_t *graph) +{ + xlator_t *trav = NULL; + xlator_t *trav_old = NULL; + + for (trav = first_of(graph);; trav = trav->next) { + if (trav_old) + xlator_destroy(trav_old); + + trav_old = trav; + + if (!trav) + break; + } +} + +static int +build_graph_generic(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict, void *param, + int (*builder)(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param)) +{ + dict_t *set_dict = NULL; + int ret = 0; + + if (mod_dict) { + set_dict = dict_copy_with_ref(volinfo->dict, NULL); + if (!set_dict) + return -1; + dict_copy(mod_dict, set_dict); + /* XXX dict_copy swallows errors */ + } else { + set_dict = volinfo->dict; + } + + ret = builder(graph, volinfo, set_dict, param); + if (!ret) + ret = volgen_graph_set_options(graph, set_dict); + + if (mod_dict) + dict_unref(set_dict); + + return ret; +} + +static gf_transport_type +transport_str_to_type(char *tt) +{ + gf_transport_type type = GF_TRANSPORT_TCP; + + if (!strcmp("tcp", tt)) + type = GF_TRANSPORT_TCP; + else if (!strcmp("rdma", tt)) + type = GF_TRANSPORT_RDMA; + else if (!strcmp("tcp,rdma", tt)) + type = GF_TRANSPORT_BOTH_TCP_RDMA; + return type; +} + +static void +transport_type_to_str(gf_transport_type type, char *tt) +{ + switch (type) { + case GF_TRANSPORT_RDMA: + strcpy(tt, "rdma"); + break; + case GF_TRANSPORT_TCP: + strcpy(tt, "tcp"); + break; + case GF_TRANSPORT_BOTH_TCP_RDMA: + strcpy(tt, "tcp,rdma"); + break; + } +} + +static void +get_vol_transport_type(glusterd_volinfo_t *volinfo, char *tt) +{ + transport_type_to_str(volinfo->transport_type, tt); +} + +#ifdef BUILD_GNFS +/* If no value has specified for tcp,rdma volume from cli + * use tcp as default value.Otherwise, use transport type + * mentioned in volinfo + */ +static void +get_vol_nfs_transport_type(glusterd_volinfo_t *volinfo, char *tt) +{ + if (volinfo->transport_type == GF_TRANSPORT_BOTH_TCP_RDMA) { + strcpy(tt, "tcp"); + gf_msg("glusterd", GF_LOG_INFO, 0, GD_MSG_DEFAULT_OPT_INFO, + "The default transport type for tcp,rdma volume " + "is tcp if option is not defined by the user "); + } else + transport_type_to_str(volinfo->transport_type, tt); +} +#endif + +/* gets the volinfo, dict, a character array for filling in + * the transport type and a boolean option which says whether + * the transport type is required for nfs or not. If its not + * for nfs, then it is considered as the client transport + * and client transport type is filled in the character array + */ +static void +get_transport_type(glusterd_volinfo_t *volinfo, dict_t *set_dict, char *transt, + gf_boolean_t is_nfs) +{ + int ret = -1; + char *tt = NULL; + + if (is_nfs == _gf_false) { + ret = dict_get_str_sizen(set_dict, "client-transport-type", &tt); + if (ret) + get_vol_transport_type(volinfo, transt); + } else { +#ifdef BUILD_GNFS + ret = dict_get_str_sizen(set_dict, "nfs.transport-type", &tt); + if (ret) + get_vol_nfs_transport_type(volinfo, transt); +#endif + } + + if (!ret) + strcpy(transt, tt); +} + +static int +server_auth_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + xlator_t *xl = NULL; + char *aa = NULL; + int ret = 0; + char *key = NULL; + char *auth_path = NULL; + + if (strcmp(vme->option, "!server-auth") != 0) + return 0; + + xl = first_of(graph); + + /* from 'auth.allow' -> 'allow', and 'auth.reject' -> 'reject' */ + key = strchr(vme->key, '.') + 1; + + ret = xlator_get_fixed_option(xl, "auth-path", &auth_path); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_DEFAULT_OPT_INFO, + "Failed to get auth-path from server graph"); + return -1; + } + ret = gf_asprintf(&aa, "auth.addr.%s.%s", auth_path, key); + if (ret != -1) { + ret = xlator_set_option(xl, aa, ret, vme->value); + GF_FREE(aa); + } + if (ret) + return -1; + + return 0; +} + +static int +loglevel_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *role = param; + struct volopt_map_entry vme2 = { + 0, + }; + + if ((strcmp(vme->option, "!client-log-level") != 0 && + strcmp(vme->option, "!brick-log-level") != 0) || + !strstr(vme->key, role)) + return 0; + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "log-level"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +threads_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *role = param; + struct volopt_map_entry vme2 = { + 0, + }; + + if ((strcmp(vme->option, "!client-threads") != 0 && + strcmp(vme->option, "!brick-threads") != 0) || + !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "threads"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +server_check_changelog_off(volgen_graph_t *graph, struct volopt_map_entry *vme, + glusterd_volinfo_t *volinfo) +{ + gf_boolean_t enabled = _gf_false; + int ret = 0; + + GF_ASSERT(volinfo); + GF_ASSERT(vme); + + if (strcmp(vme->option, "changelog") != 0) + return 0; + + ret = gf_string2boolean(vme->value, &enabled); + if (ret || enabled) + goto out; + + ret = glusterd_volinfo_get_boolean(volinfo, VKEY_CHANGELOG); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_CHANGELOG_GET_FAIL, + "failed to get the changelog status"); + ret = -1; + goto out; + } + + if (ret) { + enabled = _gf_false; + glusterd_check_geo_rep_configured(volinfo, &enabled); + + if (enabled) { + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_XLATOR_SET_OPT_FAIL, + GEOREP + " sessions active" + "for the volume %s, cannot disable changelog ", + volinfo->volname); + set_graph_errstr(graph, VKEY_CHANGELOG + " cannot be disabled " + "while " GEOREP " sessions exist"); + ret = -1; + goto out; + } + } + + ret = 0; out: - return ret; + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; } static int -__write_client_xlator (FILE *file, dict_t *dict, - char *remote_subvol, - char *remote_host, - int count, - char *last_xlator) -{ - char *volname = NULL; - char *opt_transtype = NULL; - char *opt_nodelay = NULL; - int ret = 0; - char *ping = NULL; - char *frame = NULL; - char ping_timeout[100] = {0, }; - char frame_timeout[100] = {0, }; - - const char *client_str = "volume %s-%s-%d\n" - " type protocol/client\n" - " option transport-type %s\n" - " option remote-host %s\n" - " option transport.socket.nodelay %s\n" - "%s" //for frame-timeout - "%s" //for ping-timeout - " option remote-subvolume %s\n" - "end-volume\n\n"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +server_check_marker_off(volgen_graph_t *graph, struct volopt_map_entry *vme, + glusterd_volinfo_t *volinfo) +{ + gf_boolean_t enabled = _gf_false; + int ret = 0; - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - &opt_transtype); - if (ret) { - goto out; - } + GF_ASSERT(volinfo); + GF_ASSERT(vme); - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_NODELAY, - &opt_nodelay); - if (ret) { - goto out; + if (strcmp(vme->option, "!xtime") != 0) + return 0; + + ret = gf_string2boolean(vme->value, &enabled); + if (ret || enabled) + goto out; + + ret = glusterd_volinfo_get_boolean(volinfo, VKEY_MARKER_XTIME); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_MARKER_STATUS_GET_FAIL, + "failed to get the marker status"); + ret = -1; + goto out; + } + + if (ret) { + enabled = _gf_false; + glusterd_check_geo_rep_configured(volinfo, &enabled); + + if (enabled) { + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_MARKER_DISABLE_FAIL, + GEOREP + " sessions active" + "for the volume %s, cannot disable marker ", + volinfo->volname); + set_graph_errstr(graph, VKEY_MARKER_XTIME + " cannot be disabled " + "while " GEOREP " sessions exist"); + ret = -1; + goto out; + } + } + + ret = 0; +out: + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; +} + +static int +sys_loglevel_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *role = NULL; + struct volopt_map_entry vme2 = { + 0, + }; + + role = (char *)param; + + if (strcmp(vme->option, "!sys-log-level") != 0 || !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "sys-log-level"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +logger_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *role = NULL; + struct volopt_map_entry vme2 = { + 0, + }; + + role = (char *)param; + + if (strcmp(vme->option, "!logger") != 0 || !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "logger"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +log_format_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *role = NULL; + struct volopt_map_entry vme2 = { + 0, + }; + + role = (char *)param; + + if (strcmp(vme->option, "!log-format") != 0 || !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "log-format"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +log_localtime_logging_option_handler(volgen_graph_t *graph, + struct volopt_map_entry *vme, void *param) +{ + char *role = NULL; + struct volopt_map_entry vme2 = { + 0, + }; + + role = (char *)param; + + if (strcmp(vme->option, "!cluster.localtime-logging") != 0 || + !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = GLUSTERD_LOCALTIME_LOGGING_KEY; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +log_buf_size_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *role = NULL; + struct volopt_map_entry vme2 = { + 0, + }; + + role = (char *)param; + + if (strcmp(vme->option, "!log-buf-size") != 0 || !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "log-buf-size"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +log_flush_timeout_option_handler(volgen_graph_t *graph, + struct volopt_map_entry *vme, void *param) +{ + char *role = NULL; + struct volopt_map_entry vme2 = { + 0, + }; + + role = (char *)param; + + if (strcmp(vme->option, "!log-flush-timeout") != 0 || + !strstr(vme->key, role)) + return 0; + + memcpy(&vme2, vme, sizeof(vme2)); + vme2.option = "log-flush-timeout"; + + return basic_option_handler(graph, &vme2, NULL); +} + +static int +volgen_graph_set_xl_options(volgen_graph_t *graph, dict_t *dict) +{ + int32_t ret = -1; + char *xlator = NULL; + char xlator_match[1024] = { + 0, + }; /* for posix* -> *posix* */ + char *loglevel = NULL; + xlator_t *trav = NULL; + xlator_t *this = THIS; + GF_ASSERT(this); + + ret = dict_get_str_sizen(dict, "xlator", &xlator); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "Key=xlator", NULL); + goto out; + } + + ret = dict_get_str_sizen(dict, "loglevel", &loglevel); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "Key=loglevel", NULL); + goto out; + } + + snprintf(xlator_match, 1024, "*%s", xlator); + + for (trav = first_of(graph); trav; trav = trav->next) { + if (fnmatch(xlator_match, trav->type, FNM_NOESCAPE) == 0) { + gf_msg_debug("glusterd", 0, "Setting log level for xlator: %s", + trav->type); + ret = xlator_set_fixed_option(trav, "log-level", loglevel); + if (ret) + break; } + } - if (dict_get (dict, "frame-timeout")) { - ret = dict_get_str (dict, "frame-timeout", &frame); - if (ret) { - goto out; - } - gf_log ("", GF_LOG_DEBUG, "Reconfiguring frame-timeout %s", - frame); - sprintf(frame_timeout, " option frame-timeout %s\n",frame); - } - - if (dict_get (dict, "ping-timeout")) { - ret = dict_get_str (dict, "ping-timeout", &ping); - if (ret) { - goto out; - } - gf_log ("", GF_LOG_DEBUG, "Reconfiguring ping-timeout %s", - ping); - sprintf(ping_timeout, " option ping-timeout %s\n",ping); - } - - fprintf (file, client_str, - volname, - "client", - count, - opt_transtype, - remote_host, - opt_nodelay, - frame_timeout, - ping_timeout, - remote_subvol); +out: + return ret; +} - ret = 0; +static int +server_spec_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + int ret = 0; + glusterd_volinfo_t *volinfo = NULL; + + volinfo = param; + + ret = server_auth_option_handler(graph, vme, NULL); + if (!ret) + ret = server_check_marker_off(graph, vme, volinfo); + + if (!ret) + ret = server_check_changelog_off(graph, vme, volinfo); + + if (!ret) + ret = loglevel_option_handler(graph, vme, "brick"); + + if (!ret) + ret = sys_loglevel_option_handler(graph, vme, "brick"); + + if (!ret) + ret = logger_option_handler(graph, vme, "brick"); + + if (!ret) + ret = log_format_option_handler(graph, vme, "brick"); + + if (!ret) + ret = log_buf_size_option_handler(graph, vme, "brick"); + + if (!ret) + ret = log_flush_timeout_option_handler(graph, vme, "brick"); + + if (!ret) + ret = log_localtime_logging_option_handler(graph, vme, "brick"); + + if (!ret) + ret = threads_option_handler(graph, vme, "brick"); + + return ret; +} + +static int +server_spec_extended_option_handler(volgen_graph_t *graph, + struct volopt_map_entry *vme, void *param) +{ + int ret = 0; + dict_t *dict = NULL; + + GF_ASSERT(param); + dict = (dict_t *)param; + + ret = server_auth_option_handler(graph, vme, NULL); + if (!ret) + ret = volgen_graph_set_xl_options(graph, dict); + + return ret; +} + +static void +get_vol_tstamp_file(char *filename, glusterd_volinfo_t *volinfo); + +static int +gfproxy_server_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) +{ + xlator_t *xl = NULL; + /*char *value = NULL;*/ + char transt[16] = { + 0, + }; + char key[1024] = { + 0, + }; + int keylen; + /*char port_str[7] = {0, };*/ + int ret = 0; + char *username = NULL; + char *password = NULL; + /*int rclusters = 0;*/ + + xlator_t *this = THIS; + GF_ASSERT(this); + /* We are a trusted client */ + ret = dict_set_uint32(set_dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret != 0) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; + } + + ret = dict_set_int32_sizen(set_dict, "gfproxy-server", 1); + if (ret != 0) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=gfproxy-server", NULL); + goto out; + } + + /* Build the client section of the graph first */ + build_client_graph(graph, volinfo, set_dict); + + /* Clear this setting so that future users of set_dict do not end up + * thinking they are a gfproxy server */ + dict_del_sizen(set_dict, "gfproxy-server"); + dict_del_sizen(set_dict, "trusted-client"); + + /* Then add the server to it */ + get_vol_transport_type(volinfo, transt); + xl = volgen_graph_add(graph, "protocol/server", volinfo->volname); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "transport-type", transt); + if (ret != 0) + goto out; + + /* Set username and password */ + username = glusterd_auth_get_username(volinfo); + password = glusterd_auth_get_password(volinfo); + if (username) { + keylen = snprintf(key, sizeof(key), "auth.login.gfproxyd-%s.allow", + volinfo->volname); + ret = xlator_set_option(xl, key, keylen, username); + if (ret) + return -1; + } + + if (password) { + keylen = snprintf(key, sizeof(key), "auth.login.%s.password", username); + ret = xlator_set_option(xl, key, keylen, password); + if (ret != 0) + goto out; + } - snprintf (last_xlator, 1024, "%s-%s-%d", - volname, "client", count); + snprintf(key, sizeof(key), "gfproxyd-%s", volinfo->volname); + ret = xlator_set_fixed_option(xl, "auth-path", key); out: - return ret; + return ret; } static int -__write_replace_brick_xlator (FILE *file, dict_t *dict) +brick_graph_add_posix(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) { - char *volname = NULL; - char *opt_transtype = NULL; - char *opt_nodelay = NULL; - int ret = 0; + char tmpstr[10] = { + 0, + }; + int ret = -1; + gf_boolean_t quota_enabled = _gf_true; + gf_boolean_t trash_enabled = _gf_false; + gf_boolean_t pgfid_feat = _gf_false; + char *value = NULL; + xlator_t *xl = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + + if (!graph || !volinfo || !set_dict || !brickinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + priv = this->private; + GF_VALIDATE_OR_GOTO("glusterd", priv, out); + + ret = glusterd_volinfo_get(volinfo, VKEY_FEATURES_QUOTA, &value); + if (value) { + ret = gf_string2boolean(value, "a_enabled); + if (ret) + goto out; + } + ret = glusterd_volinfo_get(volinfo, VKEY_FEATURES_TRASH, &value); + if (value) { + ret = gf_string2boolean(value, &trash_enabled); + if (ret) + goto out; + } - const char *client_str = "volume %s-%s\n" - " type protocol/client\n" - " option transport-type %s\n" - " option remote-port 34034\n" - " option transport.socket.nodelay %s\n" - "end-volume\n\n"; + ret = glusterd_volinfo_get(volinfo, "update-link-count-parent", &value); + if (value) { + ret = gf_string2boolean(value, &pgfid_feat); + if (ret) + goto out; + } - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + ret = -1; + + xl = volgen_graph_add(graph, "storage/posix", volinfo->volname); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "directory", brickinfo->path); + if (ret) + goto out; - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - &opt_transtype); + ret = xlator_set_fixed_option(xl, "volume-id", + uuid_utoa(volinfo->volume_id)); + if (ret) + goto out; + + if (quota_enabled || pgfid_feat || trash_enabled) { + ret = xlator_set_fixed_option(xl, "update-link-count-parent", "on"); if (ret) { - goto out; + goto out; } + } - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_NODELAY, - &opt_nodelay); + if (priv->op_version >= GD_OP_VERSION_7_0) { + ret = xlator_set_fixed_option(xl, "fips-mode-rchecksum", "on"); if (ret) { - goto out; + goto out; } + } + snprintf(tmpstr, sizeof(tmpstr), "%d", brickinfo->fs_share_count); + ret = xlator_set_fixed_option(xl, "shared-brick-count", tmpstr); +out: + return ret; +} - fprintf (file, client_str, - volname, - "replace-brick", - opt_transtype, - opt_nodelay); +static int +brick_graph_add_selinux(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); - ret = 0; + if (!graph || !volinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + xl = volgen_graph_add(graph, "features/selinux", volinfo->volname); + if (!xl) + goto out; + + ret = 0; out: - return ret; + return ret; } static int -__write_pump_xlator (FILE *file, dict_t *dict, - char *subvolume) +brick_graph_add_trash(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) { - char *volname = NULL; - int ret = -1; + int ret = -1; + xlator_t *xl = NULL; + + xl = volgen_graph_add(graph, "features/trash", volinfo->volname); + if (!xl) + goto out; + ret = xlator_set_fixed_option(xl, "trash-dir", ".trashcan"); + if (ret) + goto out; + ret = xlator_set_fixed_option(xl, "brick-path", brickinfo->path); + if (ret) + goto out; + ret = xlator_set_fixed_option(xl, "trash-internal-op", "off"); + if (ret) + goto out; +out: + return ret; +} - const char *pump_str = "volume %s-%s\n" - " type cluster/pump\n" - " subvolumes %s %s-replace-brick\n" - "end-volume\n\n"; +static int +brick_graph_add_arbiter(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + glusterd_brickinfo_t *last = NULL; + int ret = -1; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + if (volinfo->arbiter_count != 1) + return 0; - fprintf (file, pump_str, - volname, "pump", - subvolume, - volname); + /* Add arbiter only if it is the last (i.e. 3rd) brick. */ + last = get_last_brick_of_brick_group(volinfo, brickinfo); + if (last != brickinfo) + return 0; - ret = 0; + xl = volgen_graph_add(graph, "features/arbiter", volinfo->volname); + if (!xl) + goto out; + ret = 0; +out: + return ret; +} + +static int +brick_graph_add_bitrot_stub(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + char *value = NULL; + xlator_t *this = THIS; + + if (!graph || !volinfo || !set_dict || !brickinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/bitrot-stub", volinfo->volname); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "export", brickinfo->path); + if (ret) { + gf_log(this->name, GF_LOG_WARNING, + "failed to set the export " + "option in bit-rot-stub"); + goto out; + } + + ret = glusterd_volinfo_get(volinfo, VKEY_FEATURES_BITROT, &value); + ret = xlator_set_fixed_option(xl, "bitrot", value); + if (ret) + gf_log(this->name, GF_LOG_WARNING, + "failed to set bitrot " + "enable option in bit-rot-stub"); out: - return ret; + return ret; } static int -__write_iothreads_xlator (FILE *file, dict_t *dict, - char *subvolume) +brick_graph_add_changelog(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) { - char *volname = NULL; - char *opt_threadcount = NULL; - char *opt_autoscaling = NULL; - char *opt_minthreads = NULL; - char *opt_maxthreads = NULL; - int ret = -1; + xlator_t *xl = NULL; + char changelog_basepath[PATH_MAX] = { + 0, + }; + int ret = -1; + int32_t len = 0; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict || !brickinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/changelog", volinfo->volname); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "changelog-brick", brickinfo->path); + if (ret) + goto out; + + len = snprintf(changelog_basepath, sizeof(changelog_basepath), "%s/%s", + brickinfo->path, ".glusterfs/changelogs"); + if ((len < 0) || (len >= sizeof(changelog_basepath))) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL); + ret = -1; + goto out; + } + ret = xlator_set_fixed_option(xl, "changelog-dir", changelog_basepath); + if (ret) + goto out; + + ret = glusterd_is_bitrot_enabled(volinfo); + if (ret == -1) { + goto out; + } else if (ret) { + ret = xlator_set_fixed_option(xl, "changelog-notification", "on"); + if (ret) + goto out; + } else { + ret = xlator_set_fixed_option(xl, "changelog-notification", "off"); + if (ret) + goto out; + } +out: + return ret; +} - const char *iot_str = "volume %s-iot\n" - " type performance/io-threads\n" - " option thread-count %s\n" - "# option autoscaling %s\n" - "# option min-threads %s\n" - "# option max-threads %s\n" - " subvolumes %s\n" - "end-volume\n\n"; +static int +brick_graph_add_acl(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + ret = dict_get_str_boolean(set_dict, "features.acl", 1); + if (!ret) { + /* Skip creating this volume if option is disabled */ + /* By default, this is 'true' */ + goto out; + } else if (ret < 0) { + /* lets not treat this as error, as this option is not critical, + and implemented for debug help */ + gf_log(THIS->name, GF_LOG_INFO, + "failed to get 'features.acl' flag from dict"); + } + + xl = volgen_graph_add(graph, "features/access-control", volinfo->volname); + if (!xl) { + ret = -1; + goto out; + } + ret = 0; +out: + return ret; +} - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +static int +brick_graph_add_locks(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); - if (dict_get (dict, "thread-count")) { - gf_log("", GF_LOG_DEBUG, "Resetting the thread-count value"); - ret = dict_get_str (dict, "thread-count", &opt_threadcount); - } else - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_THREADCOUNT, - &opt_threadcount); + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } - if (ret) { - goto out; - } + xl = volgen_graph_add(graph, "features/locks", volinfo->volname); + if (!xl) + goto out; - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_AUTOSCALING, - &opt_autoscaling); - if (ret) { - goto out; - } + ret = 0; +out: + return ret; +} - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_MINTHREADS, - &opt_minthreads); - if (ret) { - goto out; - } +static int +brick_graph_add_iot(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "performance/io-threads", volinfo->volname); + if (!xl) + goto out; + ret = 0; +out: + return ret; +} - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_MAXTHREADS, - &opt_maxthreads); - if (ret) { - goto out; - } +static int +brick_graph_add_barrier(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; - fprintf (file, iot_str, - volname, - opt_threadcount, - opt_autoscaling, - opt_minthreads, - opt_maxthreads, - subvolume); + if (!graph || !volinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } - ret = 0; + xl = volgen_graph_add(graph, "features/barrier", volinfo->volname); + if (!xl) + goto out; + ret = 0; out: - return ret; + return ret; } static int -__write_access_control_xlator (FILE *file, dict_t *dict, - char *subvolume) +brick_graph_add_sdfs(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) { - char *volname = NULL; - int ret = -1; + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + if (!dict_get_str_boolean(set_dict, "features.sdfs", 0)) { + /* update only if option is enabled */ + ret = 0; + goto out; + } + + xl = volgen_graph_add(graph, "features/sdfs", volinfo->volname); + if (!xl) + goto out; + /* If we don't set this option here, the translator by default marks + it 'pass-through' */ + ret = xlator_set_fixed_option(xl, "pass-through", "false"); + if (ret) + goto out; + + ret = 0; +out: + return ret; +} - const char *ac_str = "volume %s-access-control\n" - " type features/access-control\n" - " subvolumes %s\n" - "end-volume\n\n"; +static int +brick_graph_add_namespace(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + ret = dict_get_str_boolean(set_dict, "features.tag-namespaces", 0); + if (ret == -1) + goto out; + + if (ret) { + xl = volgen_graph_add(graph, "features/namespace", volinfo->volname); + if (!xl) + goto out; + } + + ret = 0; +out: + return ret; +} - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +xlator_t * +add_one_peer(volgen_graph_t *graph, glusterd_brickinfo_t *peer, char *volname, + uint16_t index) +{ + xlator_t *kid; + + kid = volgen_graph_add_nolink(graph, "protocol/client", "%s-client-%u", + volname, index++); + if (!kid) { + return NULL; + } + + /* TBD: figure out where to get the proper transport list */ + if (xlator_set_fixed_option(kid, "transport-type", "socket")) { + return NULL; + } + if (xlator_set_fixed_option(kid, "remote-host", peer->hostname)) { + return NULL; + } + if (xlator_set_fixed_option(kid, "remote-subvolume", peer->path)) { + return NULL; + } + /* TBD: deal with RDMA, SSL */ + + return kid; +} +static int +brick_graph_add_index(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + char *pending_xattr = NULL; + char index_basepath[PATH_MAX] = {0}; + int ret = -1; + int32_t len = 0; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !brickinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/index", volinfo->volname); + if (!xl) + goto out; + + len = snprintf(index_basepath, sizeof(index_basepath), "%s/%s", + brickinfo->path, ".glusterfs/indices"); + if ((len < 0) || (len >= sizeof(index_basepath))) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL); + goto out; + } + + ret = xlator_set_fixed_option(xl, "index-base", index_basepath); + if (ret) + goto out; + if (volinfo->type == GF_CLUSTER_TYPE_DISPERSE) { + ret = xlator_set_fixed_option(xl, "xattrop64-watchlist", + "trusted.ec.dirty"); + if (ret) + goto out; + } + if ((volinfo->type == GF_CLUSTER_TYPE_REPLICATE || + volinfo->type == GF_CLUSTER_TYPE_NONE)) { + ret = xlator_set_fixed_option(xl, "xattrop-dirty-watchlist", + "trusted.afr.dirty"); + if (ret) + goto out; + ret = gf_asprintf(&pending_xattr, "trusted.afr.%s-", volinfo->volname); + if (ret < 0) + goto out; + ret = xlator_set_fixed_option(xl, "xattrop-pending-watchlist", + pending_xattr); + if (ret) + goto out; + } +out: + GF_FREE(pending_xattr); + return ret; +} - fprintf (file, ac_str, volname, subvolume); - ret = 0; +static int +brick_graph_add_marker(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *xl = NULL; + char tstamp_file[PATH_MAX] = { + 0, + }; + char volume_id[64] = { + 0, + }; + char buf[32] = { + 0, + }; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/marker", volinfo->volname); + if (!xl) + goto out; + + gf_uuid_unparse(volinfo->volume_id, volume_id); + ret = xlator_set_fixed_option(xl, "volume-uuid", volume_id); + if (ret) + goto out; + get_vol_tstamp_file(tstamp_file, volinfo); + ret = xlator_set_fixed_option(xl, "timestamp-file", tstamp_file); + if (ret) + goto out; + + snprintf(buf, sizeof(buf), "%d", volinfo->quota_xattr_version); + ret = xlator_set_fixed_option(xl, "quota-version", buf); + if (ret) + goto out; out: - return ret; + return ret; } static int -__write_server_xlator (FILE *file, dict_t *dict, - char *subvolume) +brick_graph_add_quota(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) { - char *volname = NULL; - char *opt_transtype = NULL; - char *opt_nodelay = NULL; - int ret = -1; - char *lru_count = NULL; - char inode_lru_count[100] = {0,}; + int ret = -1; + xlator_t *xl = NULL; + char *value = NULL; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/quota", volinfo->volname); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "volume-uuid", volinfo->volname); + if (ret) + goto out; + + ret = glusterd_volinfo_get(volinfo, VKEY_FEATURES_QUOTA, &value); + if (value) { + ret = xlator_set_fixed_option(xl, "server-quota", value); + if (ret) + goto out; + } +out: + return ret; +} - const char *server_str = "volume %s-%s\n" - " type protocol/server\n" - " option transport-type %s\n" - " option auth.addr.%s.allow *\n" - " option transport.socket.nodelay %s\n" - "%s"//for inode-lru-limit - " subvolumes %s\n" - "end-volume\n\n"; +static int +brick_graph_add_ro(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *xl = NULL; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + if (dict_get_str_boolean(set_dict, "features.read-only", 0) && + (dict_get_str_boolean(set_dict, "features.worm", 0) || + dict_get_str_boolean(set_dict, "features.worm-file-level", 0))) { + gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "read-only and worm cannot be set together"); + ret = -1; + goto out; + } + + xl = volgen_graph_add(graph, "features/read-only", volinfo->volname); + if (!xl) + return -1; + ret = xlator_set_fixed_option(xl, "read-only", "off"); + if (ret) + return -1; + + ret = 0; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +out: + return ret; +} - ret = dict_get_str (dict, VOLGEN_SERVER_OPTION_TRANSTYPE, - &opt_transtype); - if (ret) { - goto out; - } +static int +brick_graph_add_worm(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *xl = NULL; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + if (dict_get_str_boolean(set_dict, "features.read-only", 0) && + (dict_get_str_boolean(set_dict, "features.worm", 0) || + dict_get_str_boolean(set_dict, "features.worm-file-level", 0))) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_INCOMPATIBLE_VALUE, + "read-only and worm cannot be set together"); + ret = -1; + goto out; + } + + xl = volgen_graph_add(graph, "features/worm", volinfo->volname); + if (!xl) + return -1; + + ret = 0; - ret = dict_get_str (dict, VOLGEN_SERVER_OPTION_NODELAY, - &opt_nodelay); - if (ret) { - goto out; - } +out: + return ret; +} - if (dict_get (dict, "inode-lru-limit")) { - ret = dict_get_str (dict, "inode-lru-limit", &lru_count); - if (ret) { - goto out; - } - gf_log ("", GF_LOG_DEBUG, "Reconfiguring inode-lru-limit %s", - lru_count); - sprintf (inode_lru_count, " option inode-lru-limit %s\n", - lru_count); - } - - fprintf (file, server_str, - volname, "server", - opt_transtype, - subvolume, - opt_nodelay, - inode_lru_count, - subvolume - ); +static int +brick_graph_add_cdc(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *xl = NULL; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + /* Check for compress volume option, and add it to the graph on + * server side */ + ret = dict_get_str_boolean(set_dict, "network.compression", 0); + if (ret == -1) + goto out; + if (ret) { + xl = volgen_graph_add(graph, "features/cdc", volinfo->volname); + if (!xl) { + ret = -1; + goto out; + } + ret = xlator_set_fixed_option(xl, "mode", "server"); + if (ret) + goto out; + } +out: + return ret; +} - ret = 0; +static int +brick_graph_add_io_stats(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *xl = NULL; + xlator_t *this = THIS; + glusterd_conf_t *priv = this->private; + + if (!graph || !set_dict || !brickinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add_as(graph, "debug/io-stats", brickinfo->path); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "unique-id", brickinfo->path); + if (ret) + goto out; + + if (priv->op_version >= GD_OP_VERSION_7_1) { + ret = xlator_set_fixed_option(xl, "volume-id", + uuid_utoa(volinfo->volume_id)); + if (ret) + goto out; + } + ret = 0; out: - return ret; + return ret; } static int -__write_replicate_xlator (FILE *file, dict_t *dict, - char *subvolume, - int replicate_count, - int subvol_count, - int count, - char *last_xlator) -{ - char *volname = NULL; - char *opt_readsubvol = NULL; - char *opt_favchild = NULL; - char *opt_bckshcount = NULL; - char *opt_datash = NULL; - char *opt_datashalgo = NULL; - char *opt_shwindowsize = NULL; - char *opt_metash = NULL; - char *opt_entrysh = NULL; - char *opt_datachangelog = NULL; - char *opt_metadatachangelog = NULL; - char *opt_entrychangelog = NULL; - char *opt_strictreaddir = NULL; - char *subvol_str = NULL; - char tmp[4096] = {0,}; - int ret = -1; - int subvolume_count = 0; - int i = 0; - int len = 0; - int subvol_len = 0; - - - char replicate_str[] = "volume %s-%s-%d\n" - " type cluster/replicate\n" - "# option read-subvolume %s\n" - "# option favorite-child %s\n" - "# option background-self-heal-count %s\n" - "# option data-self-heal %s\n" - "# option data-self-heal-algorithm %s\n" - "# option data-self-heal-window-size %s\n" - "# option metadata-self-heal %s\n" - "# option entry-self-heal %s\n" - "# option data-change-log %s\n" - "# option metadata-change-log %s\n" - "# option entry-change-log %s\n" - "# option strict-readdir %s\n" - " subvolumes %s\n" - "end-volume\n\n"; - - subvolume_count = subvol_count; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +brick_graph_add_upcall(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/upcall", volinfo->volname); + if (!xl) { + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_GRAPH_FEATURE_ADD_FAIL, + "failed to add features/upcall to graph"); + goto out; + } + + ret = 0; +out: + return ret; +} - if (dict_get (dict, "read-subvolume")) { - ret = dict_get_str (dict, "read-subvolume", &opt_readsubvol); - gf_log("", GF_LOG_DEBUG, "Reconfiguring read-subvolume: %s", - &opt_readsubvol); - uncomment_option (replicate_str, - (char *) "# option read-subvolume %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_READSUBVOL, - &opt_readsubvol); - if (ret) { - goto out; - } +static int +brick_graph_add_leases(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + xl = volgen_graph_add(graph, "features/leases", volinfo->volname); + if (!xl) { + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_GRAPH_FEATURE_ADD_FAIL, + "failed to add features/leases to graph"); + goto out; + } + + ret = 0; +out: + return ret; +} - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_FAVCHILD, - &opt_favchild); +static int +brick_graph_add_server(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *xl = NULL; + char transt[16] = { + 0, + }; + char *username = NULL; + char *password = NULL; + char key[1024] = {0}; + char *ssl_user = NULL; + char *volname = NULL; + char *address_family_data = NULL; + int32_t len = 0; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict || !brickinfo) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + get_vol_transport_type(volinfo, transt); + + username = glusterd_auth_get_username(volinfo); + password = glusterd_auth_get_password(volinfo); + + xl = volgen_graph_add(graph, "protocol/server", volinfo->volname); + if (!xl) + goto out; + + ret = xlator_set_fixed_option(xl, "transport-type", transt); + if (ret) + goto out; + + /*In the case of running multiple glusterds on a single machine, + * we should ensure that bricks don't listen on all IPs on that + * machine and break the IP based separation being brought about.*/ + if (dict_get_sizen(THIS->options, "transport.socket.bind-address")) { + ret = xlator_set_fixed_option(xl, "transport.socket.bind-address", + brickinfo->hostname); + if (ret) + return -1; + } + + RPC_SET_OPT(xl, SSL_OWN_CERT_OPT, "ssl-own-cert", return -1); + RPC_SET_OPT(xl, SSL_PRIVATE_KEY_OPT, "ssl-private-key", return -1); + RPC_SET_OPT(xl, SSL_CA_LIST_OPT, "ssl-ca-list", return -1); + RPC_SET_OPT(xl, SSL_CRL_PATH_OPT, "ssl-crl-path", return -1); + RPC_SET_OPT(xl, SSL_CERT_DEPTH_OPT, "ssl-cert-depth", return -1); + RPC_SET_OPT(xl, SSL_CIPHER_LIST_OPT, "ssl-cipher-list", return -1); + RPC_SET_OPT(xl, SSL_DH_PARAM_OPT, "ssl-dh-param", return -1); + RPC_SET_OPT(xl, SSL_EC_CURVE_OPT, "ssl-ec-curve", return -1); + + if (dict_get_str_sizen(volinfo->dict, "transport.address-family", + &address_family_data) == 0) { + ret = xlator_set_fixed_option(xl, "transport.address-family", + address_family_data); if (ret) { - goto out; + gf_log("glusterd", GF_LOG_WARNING, + "failed to set transport.address-family"); + return -1; } + } - if (dict_get (dict, "background-self-heal-count")) { - ret = dict_get_str (dict,"background-self-heal-count", - &opt_bckshcount); - gf_log("", GF_LOG_DEBUG, "Reconfiguring background-self-heal-" - "count: %s", &opt_bckshcount); - uncomment_option (replicate_str, - (char *) "# option background-self-heal-count %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_BCKSHCOUNT, - &opt_bckshcount); - if (ret) { - goto out; + if (username) { + len = snprintf(key, sizeof(key), "auth.login.%s.allow", + brickinfo->path); + if ((len < 0) || (len >= sizeof(key))) { + return -1; } - if (dict_get (dict, "data-self-heal")) { - ret = dict_get_str (dict,"data-self-heal", - &opt_datash); - gf_log("", GF_LOG_DEBUG, "Reconfiguring data-self-heal" - "count: %s", &opt_datash); - uncomment_option (replicate_str, - (char *) "# option data-self-heal %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_DATASH, - &opt_datash); - if (ret) { - goto out; - } + ret = xlator_set_option(xl, key, len, username); + if (ret) + return -1; + } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_DATASHALGO, - &opt_datashalgo); - if (ret) { - goto out; + if (password) { + len = snprintf(key, sizeof(key), "auth.login.%s.password", username); + if ((len < 0) || (len >= sizeof(key))) { + return -1; } + ret = xlator_set_option(xl, key, len, password); + if (ret) + return -1; + } - if (dict_get (dict, "data-self-heal-window-size")) { - ret = dict_get_str (dict,"data-self-heal-window-size", - &opt_shwindowsize); - gf_log("", GF_LOG_DEBUG, "Reconfiguring data-self-heal" - "window-size: %s", &opt_shwindowsize); - uncomment_option (replicate_str, - (char *) "# option data-self-heal-window-size %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_SHWINDOWSIZE, - &opt_shwindowsize); - if (ret) { - goto out; - } + ret = xlator_set_fixed_option(xl, "auth-path", brickinfo->path); + if (ret) + return -1; - if (dict_get (dict, "metadata-self-heal")) { - ret = dict_get_str (dict,"metadata-self-heal", - &opt_metash); - gf_log("", GF_LOG_DEBUG, "Reconfiguring metadata-self-heal" - "count: %s", &opt_metash); - uncomment_option (replicate_str, - (char *) "# option metadata-self-heal %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_METASH, - &opt_metash); - if (ret) { - goto out; - } - - if (dict_get (dict, "entry-self-heal")) { - ret = dict_get_str (dict,"entry-self-heal", - &opt_entrysh); - gf_log("", GF_LOG_DEBUG, "Reconfiguring entry-self-heal" - "count: %s", &opt_entrysh); - uncomment_option (replicate_str, - (char *) "# option entry-self-heal %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_ENTRYSH, - &opt_entrysh); - if (ret) { - goto out; - } + volname = volinfo->is_snap_volume ? volinfo->parent_volname + : volinfo->volname; - if (dict_get (dict, "data-change-log")) { - ret = dict_get_str (dict,"data-change-log", - &opt_datachangelog); - gf_log("", GF_LOG_DEBUG, "Reconfiguring data-change-log" - "count: %s", &opt_datachangelog); - uncomment_option (replicate_str, - (char *) "# option data-change-log %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_DATACHANGELOG, - &opt_datachangelog); - if (ret) { - goto out; - } + if (volname && !strcmp(volname, GLUSTER_SHARED_STORAGE)) { + ret = xlator_set_fixed_option(xl, "strict-auth-accept", "true"); + if (ret) + return -1; + } - if (dict_get (dict, "metadata-change-log")) { - ret = dict_get_str (dict,"metadata-change-log", - &opt_metadatachangelog); - gf_log("", GF_LOG_DEBUG, "Reconfiguring metadata-change-log" - "count: %s", &opt_metadatachangelog); - uncomment_option (replicate_str, - (char *) "# option metadata-change-log %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_METADATACHANGELOG, - &opt_metadatachangelog); - if (ret) { - goto out; + if (dict_get_str_sizen(volinfo->dict, "auth.ssl-allow", &ssl_user) == 0) { + len = snprintf(key, sizeof(key), "auth.login.%s.ssl-allow", + brickinfo->path); + if ((len < 0) || (len >= sizeof(key))) { + return -1; } - if (dict_get (dict, "entry-change-log")) { - ret = dict_get_str (dict, "entry-change-log", &opt_entrychangelog); - gf_log("", GF_LOG_DEBUG, "Reconfiguring entry-change-log: %s", - &opt_entrychangelog); - uncomment_option (replicate_str, - (char *) "# option entry-change-log %s\n"); - } - else + ret = xlator_set_option(xl, key, len, ssl_user); + if (ret) + return -1; + } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_ENTRYCHANGELOG, - &opt_entrychangelog); - if (ret) { - goto out; +out: + return ret; +} + +static int +brick_graph_add_pump(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + int pump = 0; + xlator_t *xl = NULL; + xlator_t *txl = NULL; + xlator_t *rbxl = NULL; + char *username = NULL; + char *password = NULL; + char *ptranst = NULL; + char *address_family_data = NULL; + xlator_t *this = THIS; + GF_ASSERT(this); + + if (!graph || !volinfo || !set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + goto out; + } + + ret = dict_get_int32(volinfo->dict, "enable-pump", &pump); + if (ret == -ENOENT) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "Key=enable-pump", NULL); + ret = pump = 0; + } + if (ret) + return -1; + + username = glusterd_auth_get_username(volinfo); + password = glusterd_auth_get_password(volinfo); + + if (pump) { + txl = first_of(graph); + + rbxl = volgen_graph_add_nolink(graph, "protocol/client", + "%s-replace-brick", volinfo->volname); + if (!rbxl) + return -1; + + ptranst = glusterd_get_trans_type_rb(volinfo->transport_type); + if (NULL == ptranst) + return -1; + + RPC_SET_OPT(rbxl, SSL_OWN_CERT_OPT, "ssl-own-cert", return -1); + RPC_SET_OPT(rbxl, SSL_PRIVATE_KEY_OPT, "ssl-private-key", return -1); + RPC_SET_OPT(rbxl, SSL_CA_LIST_OPT, "ssl-ca-list", return -1); + RPC_SET_OPT(rbxl, SSL_CRL_PATH_OPT, "ssl-crl-path", return -1); + RPC_SET_OPT(rbxl, SSL_CERT_DEPTH_OPT, "ssl-cert-depth", return -1); + RPC_SET_OPT(rbxl, SSL_CIPHER_LIST_OPT, "ssl-cipher-list", return -1); + RPC_SET_OPT(rbxl, SSL_DH_PARAM_OPT, "ssl-dh-param", return -1); + RPC_SET_OPT(rbxl, SSL_EC_CURVE_OPT, "ssl-ec-curve", return -1); + + if (username) { + ret = xlator_set_fixed_option(rbxl, "username", username); + if (ret) + return -1; } - if (dict_get (dict, "strict-readdir")) { - ret = dict_get_str (dict,"strict-readdir", - &opt_strictreaddir); - gf_log("", GF_LOG_DEBUG, "Reconfiguring sstrict-readdir" - "count: %s", &opt_strictreaddir); - uncomment_option (replicate_str, - (char *) "# option strict-readdir %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_STRICTREADDIR, - &opt_strictreaddir); - if (ret) { - goto out; + if (password) { + ret = xlator_set_fixed_option(rbxl, "password", password); + if (ret) + return -1; } - for (i = 0; i < replicate_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, - subvolume_count); - len = strlen (tmp); - subvol_len += len; - subvolume_count++; + ret = xlator_set_fixed_option(rbxl, "transport-type", ptranst); + GF_FREE(ptranst); + if (ret) + return -1; + + if (dict_get_str_sizen(volinfo->dict, "transport.address-family", + &address_family_data) == 0) { + ret = xlator_set_fixed_option(rbxl, "transport.address-family", + address_family_data); + if (ret) { + gf_log("glusterd", GF_LOG_WARNING, + "failed to set transport.address-family"); + return -1; + } } - subvolume_count = subvol_count; - subvol_len++; + xl = volgen_graph_add_nolink(graph, "cluster/pump", "%s-pump", + volinfo->volname); + if (!xl) + return -1; + ret = volgen_xlator_link(xl, txl); + if (ret) + return -1; + ret = volgen_xlator_link(xl, rbxl); + if (ret) + return -1; + } - subvol_str = GF_CALLOC (1, subvol_len, gf_gld_mt_char); - if (!subvol_str) { - gf_log ("glusterd", GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; - } +out: + return ret; +} - for (i = 0; i < replicate_count ; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, - subvolume_count); - strncat (subvol_str, tmp, strlen (tmp)); - subvolume_count++; - } - - fprintf (file, replicate_str, - volname, - "replicate", - count, - opt_readsubvol, - opt_favchild, - opt_bckshcount, - opt_datash, - opt_datashalgo, - opt_shwindowsize, - opt_metash, - opt_entrysh, - opt_datachangelog, - opt_metadatachangelog, - opt_entrychangelog, - opt_strictreaddir, - subvol_str); +/* The order of xlator definition here determines + * the topology of the brick graph */ +static volgen_brick_xlator_t server_graph_table[] = { + {brick_graph_add_server, NULL}, + {brick_graph_add_io_stats, "NULL"}, + {brick_graph_add_sdfs, "sdfs"}, + {brick_graph_add_namespace, "namespace"}, + {brick_graph_add_cdc, NULL}, + {brick_graph_add_quota, "quota"}, + {brick_graph_add_index, "index"}, + {brick_graph_add_barrier, NULL}, + {brick_graph_add_marker, "marker"}, + {brick_graph_add_selinux, "selinux"}, + {brick_graph_add_iot, "io-threads"}, + {brick_graph_add_upcall, "upcall"}, + {brick_graph_add_leases, "leases"}, + {brick_graph_add_pump, NULL}, + {brick_graph_add_ro, NULL}, + {brick_graph_add_worm, NULL}, + {brick_graph_add_locks, "locks"}, + {brick_graph_add_acl, "acl"}, + {brick_graph_add_bitrot_stub, "bitrot-stub"}, + {brick_graph_add_changelog, "changelog"}, + {brick_graph_add_trash, "trash"}, + {brick_graph_add_arbiter, "arbiter"}, + {brick_graph_add_posix, "posix"}, +}; + +static glusterd_server_xlator_t +get_server_xlator(char *xlator) +{ + int i = 0; + int size = sizeof(server_graph_table) / sizeof(server_graph_table[0]); + for (i = 0; i < size; i++) { + if (!server_graph_table[i].dbg_key) + continue; + if (strcmp(xlator, server_graph_table[i].dbg_key)) + return GF_XLATOR_SERVER; + } - ret = 0; + return GF_XLATOR_NONE; +} - snprintf (last_xlator, 1024, "%s-%s-%d", - volname, "replicate", count); +static glusterd_client_xlator_t +get_client_xlator(char *xlator) +{ + glusterd_client_xlator_t subvol = GF_CLNT_XLATOR_NONE; -out: - if (subvol_str) - GF_FREE (subvol_str); - return ret; + if (strcmp(xlator, "client") == 0) + subvol = GF_CLNT_XLATOR_FUSE; + + return subvol; } static int -__write_stripe_xlator (FILE *file, dict_t *dict, - char *subvolume, - int stripe_count, - int subvol_count, - int count, - char *last_xlator) +debugxl_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) { - char *volname = NULL; - char *opt_blocksize = NULL; - char *opt_usexattr = NULL; - char *subvol_str = NULL; - char tmp[4096] = {0,}; - int subvolume_count = 0; - int ret = -1; - int i = 0; - int subvol_len = 0; - int len = 0; + char *volname = NULL; + gf_boolean_t enabled = _gf_false; - char stripe_str[] = "volume %s-%s-%d\n" - " type cluster/stripe\n" - "# option block-size %s\n" - "# option use-xattr %s\n" - " subvolumes %s\n" - "end-volume\n\n"; + volname = param; - subvolume_count = subvol_count; + if (strcmp(vme->option, "!debug") != 0) + return 0; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + if (!strcmp(vme->key, "debug.trace") || + !strcmp(vme->key, "debug.error-gen") || + !strcmp(vme->key, "debug.delay-gen")) { + if (get_server_xlator(vme->value) == GF_XLATOR_NONE && + get_client_xlator(vme->value) == GF_CLNT_XLATOR_NONE) + return 0; + } + + if (gf_string2boolean(vme->value, &enabled) == -1) + goto add_graph; + if (!enabled) + return 0; - if (dict_get (dict, "block-size")) { - ret = dict_get_str (dict, "block-size", &opt_blocksize); - gf_log("", GF_LOG_DEBUG, "Reconfiguring Stripe Count %s", - opt_blocksize); - uncomment_option (stripe_str, - (char *) "# option block-size %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_STRIPE_OPTION_BLOCKSIZE, - &opt_blocksize); - if (ret) { - goto out; +add_graph: + if (strcmp(vme->value, "off") == 0) + return 0; + if (volgen_graph_add(graph, vme->voltype, volname)) + return 0; + else + return -1; +} + +int +check_and_add_debug_xl(volgen_graph_t *graph, dict_t *set_dict, char *volname, + char *xlname) +{ + int i = 0; + int ret = 0; + char *value_str = NULL; + static char *xls[] = {"debug.trace", "debug.error-gen", "debug.delay-gen", + NULL}; + + if (!xlname) + goto out; + + while (xls[i]) { + ret = dict_get_str(set_dict, xls[i], &value_str); + if (!ret) { + if (strcmp(xlname, value_str) == 0) { + ret = volgen_graph_set_options_generic(graph, set_dict, volname, + &debugxl_option_handler); + if (ret) + goto out; + } } + i++; + } + ret = 0; - ret = dict_get_str (dict, VOLGEN_STRIPE_OPTION_USEXATTR, - &opt_usexattr); +out: + return ret; +} + +static int +server_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) +{ + int ret = 0; + char *xlator = NULL; + char *loglevel = NULL; + int i = 0; + + i = sizeof(server_graph_table) / sizeof(server_graph_table[0]) - 1; + + while (i >= 0) { + ret = server_graph_table[i].builder(graph, volinfo, set_dict, param); if (ret) { - goto out; + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_BUILD_GRAPH_FAILED, + "Builing graph " + "failed for server graph table entry: %d", + i); + goto out; } + ret = check_and_add_debug_xl(graph, set_dict, volinfo->volname, + server_graph_table[i].dbg_key); + if (ret) + goto out; - for (i = 0; i < stripe_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, subvolume_count); - len = strlen (tmp); - subvol_len += len; - subvolume_count++; - } + i--; + } - subvolume_count = subvol_count; - subvol_len++; + ret = dict_get_str_sizen(set_dict, "xlator", &xlator); - subvol_str = GF_CALLOC (1, subvol_len, gf_gld_mt_char); - if (!subvol_str) { - gf_log ("glusterd", GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; + /* got a cli log level request */ + if (!ret) { + ret = dict_get_str_sizen(set_dict, "loglevel", &loglevel); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "could not get both" + " translator name and loglevel for log level request"); + goto out; } + } - for (i = 0; i < stripe_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, subvolume_count); - strncat (subvol_str, tmp, strlen (tmp)); - subvolume_count++; - } + ret = volgen_graph_set_options_generic( + graph, set_dict, (xlator && loglevel) ? (void *)set_dict : volinfo, + (xlator && loglevel) ? &server_spec_extended_option_handler + : &server_spec_option_handler); - fprintf (file, stripe_str, - volname, - "stripe", - count, - opt_blocksize, - opt_usexattr, - subvol_str); +out: + return ret; +} +/* builds a graph for server role , with option overrides in mod_dict */ +static int +build_server_graph(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict, glusterd_brickinfo_t *brickinfo) +{ + return build_graph_generic(graph, volinfo, mod_dict, brickinfo, + &server_graph_builder); +} - ret = 0; +static int +perfxl_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + gf_boolean_t enabled = _gf_false; + glusterd_volinfo_t *volinfo = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + GF_VALIDATE_OR_GOTO("glusterd", param, out); + volinfo = param; + this = THIS; + GF_VALIDATE_OR_GOTO("glusterd", this, out); + priv = this->private; + GF_VALIDATE_OR_GOTO("glusterd", priv, out); + + if (strcmp(vme->option, "!perf") != 0) + return 0; + + if (gf_string2boolean(vme->value, &enabled) == -1) + return -1; + if (!enabled) + return 0; - snprintf (last_xlator, 1024, "%s-%s-%d", - volname, "stripe", count); + /* Check op-version before adding the 'open-behind' xlator in the graph + */ + if (!strcmp(vme->key, "performance.open-behind") && + (vme->op_version > volinfo->client_op_version)) + return 0; + + if (priv->op_version < GD_OP_VERSION_3_12_2) { + /* For replicate volumes do not load io-threads as it affects + * performance + */ + if (!strcmp(vme->key, "performance.client-io-threads") && + (GF_CLUSTER_TYPE_REPLICATE == volinfo->type)) + return 0; + } + + /* if VKEY_READDIR_AHEAD is enabled and parallel readdir is + * not enabled then load readdir-ahead here else it will be + * loaded as a child of dht */ + if (!strcmp(vme->key, VKEY_READDIR_AHEAD) && + glusterd_volinfo_get_boolean(volinfo, VKEY_PARALLEL_READDIR)) + return 0; + if (volgen_graph_add(graph, vme->voltype, volinfo->volname)) + return 0; out: - if (subvol_str) - GF_FREE (subvol_str); - return ret; - -} - -static int -__write_distribute_xlator (FILE *file, dict_t *dict, - char *subvolume, - int dist_count, - char *last_xlator) -{ - char *volname = NULL; - char *subvol_str = NULL; - char tmp[4096] = {0,}; - char *opt_lookupunhash = NULL; - char *opt_minfreedisk = NULL; - char *opt_unhashsticky = NULL; - int ret = -1; - int i = 0; - int subvol_len = 0; - int len = 0; - - char dht_str[] = "volume %s-%s\n" - "type cluster/distribute\n" - "# option lookup-unhashed %s\n" - "# option min-free-disk %s\n" - "# option unhashed-sticky-bit %s\n" - " subvolumes %s\n" - "end-volume\n\n"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + return -1; +} - if (dict_get (dict, "lookup-unhashed")) { - ret = dict_get_str (dict, "lookup-unhashed", &opt_lookupunhash); - gf_log("", GF_LOG_DEBUG, "Reconfiguring lookup-unhashed %s", - opt_lookupunhash); - uncomment_option (dht_str, - (char *) "# option lookup-unhashed %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_DHT_OPTION_LOOKUPUNHASH, - &opt_lookupunhash); - if (ret) { - goto out; - } +static int +gfproxy_server_perfxl_option_handler(volgen_graph_t *graph, + struct volopt_map_entry *vme, void *param) +{ + GF_ASSERT(param); - if (dict_get (dict, "min-free-disk")) { - ret = dict_get_str (dict, "min-free-disk", &opt_minfreedisk); - gf_log("", GF_LOG_DEBUG, "Reconfiguring min-free-disk", - opt_minfreedisk); - uncomment_option (dht_str, - (char *) "# option min-free-disk %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_DHT_OPTION_MINFREEDISK, - &opt_minfreedisk); - if (ret) { - goto out; - } + /* write-behind is the *not* allowed for gfproxy-servers */ + if (strstr(vme->key, "write-behind")) { + return 0; + } - ret = dict_get_str (dict, VOLGEN_DHT_OPTION_UNHASHSTICKY, - &opt_unhashsticky); - if (ret) { - goto out; - } + perfxl_option_handler(graph, vme, param); - for (i = 0; i < dist_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, i); - len = strlen (tmp); - subvol_len += len; - } + return 0; +} - subvol_len++; - subvol_str = GF_CALLOC (1, subvol_len, gf_gld_mt_char); - if (!subvol_str) { - gf_log ("glusterd", GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; - } +static int +gfproxy_client_perfxl_option_handler(volgen_graph_t *graph, + struct volopt_map_entry *vme, void *param) +{ + GF_ASSERT(param); - for (i = 0; i < dist_count ; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, i); - strncat (subvol_str, tmp, strlen (tmp)); - } + /* write-behind is the only allowed "perf" for gfproxy-clients */ + if (!strstr(vme->key, "write-behind")) + return 0; - fprintf (file, dht_str, - volname, - "dht", - opt_lookupunhash, - opt_minfreedisk, - opt_unhashsticky, - subvol_str); + perfxl_option_handler(graph, vme, param); + return 0; +} - ret = 0; +#ifdef BUILD_GNFS +static int +nfsperfxl_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *volname = NULL; + gf_boolean_t enabled = _gf_false; + + volname = param; - snprintf (last_xlator, 1024, "%s-%s", - volname, "dht"); + if (strcmp(vme->option, "!nfsperf") != 0) + return 0; + + if (gf_string2boolean(vme->value, &enabled) == -1) + return -1; + if (!enabled) + return 0; + + if (volgen_graph_add(graph, vme->voltype, volname)) + return 0; + else + return -1; +} +#endif +#if (HAVE_LIB_XML) +int +end_sethelp_xml_doc(xmlTextWriterPtr writer) +{ + int ret = -1; + + ret = xmlTextWriterEndElement(writer); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_TEXT_WRITE_FAIL, + "Could not end an " + "xmlElement"); + ret = -1; + goto out; + } + ret = xmlTextWriterEndDocument(writer); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_TEXT_WRITE_FAIL, + "Could not end an " + "xmlDocument"); + ret = -1; + goto out; + } + ret = 0; out: - if (subvol_str) - GF_FREE (subvol_str); - return ret; + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; } +int +init_sethelp_xml_doc(xmlTextWriterPtr *writer, xmlBufferPtr *buf) +{ + int ret = -1; + + if (!writer || !buf) + goto out; + + *buf = xmlBufferCreateSize(8192); + if (buf == NULL) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Error creating the xml " + "buffer"); + ret = -1; + goto out; + } + + xmlBufferSetAllocationScheme(*buf, XML_BUFFER_ALLOC_DOUBLEIT); + + *writer = xmlNewTextWriterMemory(*buf, 0); + if (writer == NULL) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + " Error creating the xml " + "writer"); + ret = -1; + goto out; + } + + ret = xmlTextWriterStartDocument(*writer, "1.0", "UTF-8", "yes"); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_DOC_START_FAIL, + "Error While starting the " + "xmlDoc"); + goto out; + } + + ret = xmlTextWriterStartElement(*writer, (xmlChar *)"options"); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_ELE_CREATE_FAIL, + "Could not create an " + "xmlElement"); + ret = -1; + goto out; + } + + ret = 0; + +out: + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; +} int -uncomment_option( char *opt_str,char *comment_str) +xml_add_volset_element(xmlTextWriterPtr writer, const char *name, + const char *def_val, const char *dscrpt) { - char *ptr; + int ret = -1; + + GF_ASSERT(name); + + ret = xmlTextWriterStartElement(writer, (xmlChar *)"option"); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_ELE_CREATE_FAIL, + "Could not create an " + "xmlElemetnt"); + ret = -1; + goto out; + } + + ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"defaultValue", + "%s", def_val); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_ELE_CREATE_FAIL, + "Could not create an " + "xmlElemetnt"); + ret = -1; + goto out; + } + + ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"description", + "%s", dscrpt); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_ELE_CREATE_FAIL, + "Could not create an " + "xmlElemetnt"); + ret = -1; + goto out; + } + + ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s", + name); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_ELE_CREATE_FAIL, + "Could not create an " + "xmlElemetnt"); + ret = -1; + goto out; + } + + ret = xmlTextWriterEndElement(writer); + if (ret < 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_XML_ELE_CREATE_FAIL, + "Could not end an " + "xmlElemetnt"); + ret = -1; + goto out; + } + + ret = 0; +out: + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; +} - ptr = strstr (opt_str,comment_str); - if (!ptr) - return -1; - - if (*ptr != '#') - return -1; +#endif - *ptr = ' '; +int +_get_xlator_opt_key_from_vme(struct volopt_map_entry *vme, char **key) +{ + int ret = 0; + + GF_ASSERT(vme); + GF_ASSERT(key); + + if (!strcmp(vme->key, AUTH_ALLOW_MAP_KEY)) + *key = gf_strdup(AUTH_ALLOW_OPT_KEY); + else if (!strcmp(vme->key, AUTH_REJECT_MAP_KEY)) + *key = gf_strdup(AUTH_REJECT_OPT_KEY); +#ifdef BUILD_GNFS + else if (!strcmp(vme->key, NFS_DISABLE_MAP_KEY)) + *key = gf_strdup(NFS_DISABLE_OPT_KEY); +#endif + else { + if (vme->option) { + if (vme->option[0] == '!') { + *key = vme->option + 1; + if (!*key[0]) + ret = -1; + } else { + *key = vme->option; + } + } else { + *key = strchr(vme->key, '.'); + if (*key) { + (*key)++; + if (!*key[0]) + ret = -1; + } else { + ret = -1; + } + } + } + if (ret) + gf_msg("glusterd", GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, + "Wrong entry found in " + "glusterd_volopt_map entry %s", + vme->key); + else + gf_msg_debug("glusterd", 0, "Returning %d", ret); + + return ret; +} - return 0; -} +void +_free_xlator_opt_key(char *key) +{ + GF_ASSERT(key); -static int -__write_wb_xlator (FILE *file, dict_t *dict, - char *subvolume) + if (!strcmp(key, AUTH_ALLOW_OPT_KEY) || !strcmp(key, AUTH_REJECT_OPT_KEY) || + !strcmp(key, NFS_DISABLE_OPT_KEY)) + GF_FREE(key); + + return; +} + +static xlator_t * +volgen_graph_build_client(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + char *hostname, char *port, char *subvol, char *xl_id, + char *transt, dict_t *set_dict) { - char *volname = NULL; - char *opt_flushbehind = NULL; - char *opt_cachesize = NULL; - char *opt_disablenbytes = NULL; - char *opt_osync = NULL; - char *opt_tricklingwrites = NULL; - int ret = -1; + xlator_t *xl = NULL; + int ret = -2; + uint32_t client_type = GF_CLIENT_OTHER; + char *str = NULL; + char *ssl_str = NULL; + gf_boolean_t ssl_bool = _gf_false; + char *address_family_data = NULL; + + GF_ASSERT(graph); + GF_ASSERT(subvol); + GF_ASSERT(xl_id); + GF_ASSERT(transt); + + xl = volgen_graph_add_nolink(graph, "protocol/client", "%s", xl_id); + if (!xl) + goto err; + + ret = xlator_set_fixed_option(xl, "ping-timeout", "42"); + if (ret) + goto err; + + if (hostname) { + ret = xlator_set_fixed_option(xl, "remote-host", hostname); + if (ret) + goto err; + } - char dht_str[] = "volume %s-%s\n" - " type performance/write-behind\n" - "# option flush-behind %s\n" - "# option cache-size %s\n" - "# option disable-for-first-nbytes %s\n" - "# option enable-O_SYNC %s\n" - "# option enable-trickling-writes %s\n" - " subvolumes %s\n" - "end-volume\n\n"; + if (port) { + ret = xlator_set_fixed_option(xl, "remote-port", port); + if (ret) + goto err; + } - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + ret = xlator_set_fixed_option(xl, "remote-subvolume", subvol); + if (ret) + goto err; - ret = dict_get_str (dict, VOLGEN_WB_OPTION_FLUSHBEHIND, - &opt_flushbehind); - if (ret) { - goto out; - } + ret = xlator_set_fixed_option(xl, "transport-type", transt); + if (ret) + goto err; - if (dict_get (dict, "cache-size")) { - gf_log("",GF_LOG_DEBUG, "Uncommenting option cache-size"); - uncomment_option (dht_str,(char *) "# option cache-size %s\n"); - ret = dict_get_str (dict, "cache-size", &opt_cachesize); - } - else - ret = dict_get_str (dict, VOLGEN_WB_OPTION_CACHESIZE, - &opt_cachesize); + if (dict_get_str_sizen(volinfo->dict, "transport.address-family", + &address_family_data) == 0) { + ret = xlator_set_fixed_option(xl, "transport.address-family", + address_family_data); if (ret) { - goto out; + gf_log("glusterd", GF_LOG_WARNING, + "failed to set transport.address-family"); + goto err; } + } - ret = dict_get_str (dict, VOLGEN_WB_OPTION_DISABLENBYTES, - &opt_disablenbytes); - if (ret) { - goto out; - } + ret = dict_get_uint32(set_dict, "trusted-client", &client_type); - ret = dict_get_str (dict, VOLGEN_WB_OPTION_OSYNC, - &opt_osync); - if (ret) { - goto out; + if (!ret && (client_type == GF_CLIENT_TRUSTED || + client_type == GF_CLIENT_TRUSTED_PROXY)) { + str = NULL; + str = glusterd_auth_get_username(volinfo); + if (str) { + ret = xlator_set_fixed_option(xl, "username", str); + if (ret) + goto err; } - ret = dict_get_str (dict, VOLGEN_WB_OPTION_TRICKLINGWRITES, - &opt_tricklingwrites); - if (ret) { - goto out; + str = glusterd_auth_get_password(volinfo); + if (str) { + ret = xlator_set_fixed_option(xl, "password", str); + if (ret) + goto err; } + } - fprintf (file, dht_str, - volname, - "write-behind", - opt_flushbehind, - opt_cachesize, - opt_disablenbytes, - opt_osync, - opt_tricklingwrites, - subvolume); + if (dict_get_str_sizen(set_dict, "client.ssl", &ssl_str) == 0) { + if (gf_string2boolean(ssl_str, &ssl_bool) == 0) { + if (ssl_bool) { + ret = xlator_set_fixed_option( + xl, "transport.socket.ssl-enabled", "true"); + if (ret) { + goto err; + } + } + } + } + + RPC_SET_OPT(xl, SSL_OWN_CERT_OPT, "ssl-own-cert", goto err); + RPC_SET_OPT(xl, SSL_PRIVATE_KEY_OPT, "ssl-private-key", goto err); + RPC_SET_OPT(xl, SSL_CA_LIST_OPT, "ssl-ca-list", goto err); + RPC_SET_OPT(xl, SSL_CRL_PATH_OPT, "ssl-crl-path", goto err); + RPC_SET_OPT(xl, SSL_CERT_DEPTH_OPT, "ssl-cert-depth", goto err); + RPC_SET_OPT(xl, SSL_CIPHER_LIST_OPT, "ssl-cipher-list", goto err); + RPC_SET_OPT(xl, SSL_DH_PARAM_OPT, "ssl-dh-param", goto err); + RPC_SET_OPT(xl, SSL_EC_CURVE_OPT, "ssl-ec-curve", goto err); + + return xl; +err: + return NULL; +} +static int +volgen_graph_build_clients(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) +{ + int i = 0; + int ret = -1; + char transt[16] = { + 0, + }; + glusterd_brickinfo_t *brick = NULL; + glusterd_brickinfo_t *ta_brick = NULL; + xlator_t *xl = NULL; + int subvol_index = 0; + int thin_arbiter_index = 0; + + if (volinfo->brick_count == 0) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLUME_INCONSISTENCY, + "volume inconsistency: brick count is 0"); + goto out; + } + + if ((volinfo->dist_leaf_count < volinfo->brick_count) && + ((volinfo->brick_count % volinfo->dist_leaf_count) != 0)) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLUME_INCONSISTENCY, + "volume inconsistency: " + "total number of bricks (%d) is not divisible with " + "number of bricks per cluster (%d) in a multi-cluster " + "setup", + volinfo->brick_count, volinfo->dist_leaf_count); + goto out; + } + + get_transport_type(volinfo, set_dict, transt, _gf_false); + + if (!strcmp(transt, "tcp,rdma")) + strcpy(transt, "tcp"); + + i = 0; + cds_list_for_each_entry(brick, &volinfo->bricks, brick_list) + { + /* insert ta client xlator entry. + * eg - If subvol count is > 1, then after every two client xlator + * entries there should be a ta client xlator entry in the volfile. ta + * client xlator indexes are - 2, 5, 8 etc depending on the index of + * subvol. + */ + if (volinfo->thin_arbiter_count && + (i + 1) % (volinfo->replica_count + 1) == 0) { + thin_arbiter_index = 0; + cds_list_for_each_entry(ta_brick, &volinfo->ta_bricks, brick_list) + { + if (thin_arbiter_index == subvol_index) { + xl = volgen_graph_build_client( + graph, volinfo, ta_brick->hostname, NULL, + ta_brick->path, ta_brick->brick_id, transt, set_dict); + if (!xl) { + ret = -1; + goto out; + } + } + thin_arbiter_index++; + } + subvol_index++; + } + xl = volgen_graph_build_client(graph, volinfo, brick->hostname, NULL, + brick->path, brick->brick_id, transt, + set_dict); + if (!xl) { + ret = -1; + goto out; + } + + i++; + } + + /* Add ta client xlator entry for last subvol + * Above loop will miss out on making the ta client + * xlator entry for the last subvolume in the volfile + */ + if (volinfo->thin_arbiter_count) { + thin_arbiter_index = 0; + cds_list_for_each_entry(ta_brick, &volinfo->ta_bricks, brick_list) + { + if (thin_arbiter_index == subvol_index) { + xl = volgen_graph_build_client( + graph, volinfo, ta_brick->hostname, NULL, ta_brick->path, + ta_brick->brick_id, transt, set_dict); + if (!xl) { + ret = -1; + goto out; + } + } - ret = 0; + thin_arbiter_index++; + } + } + + if (i != volinfo->brick_count) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLUME_INCONSISTENCY, + "volume inconsistency: actual number of bricks (%d) " + "differs from brick count (%d)", + i, volinfo->brick_count); + ret = -1; + goto out; + } + ret = 0; out: - return ret; + return ret; } static int -__write_ra_xlator (FILE *file, dict_t *dict, - char *subvolume) +volgen_link_bricks(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + char *xl_type, char *xl_namefmt, size_t child_count, + size_t sub_count, size_t start_count, xlator_t *trav) { - char *volname = NULL; - char *opt_atime = NULL; - char *opt_pagecount = NULL; - int ret = -1; + int i = 0; + int j = start_count; + xlator_t *xl = NULL; + char *volname = NULL; + int ret = -1; - const char *ra_str = "volume %s-%s\n" - " type performance/read-ahead\n" - "# option force-atime-update %s\n" - "# option page-count %s\n" - " subvolumes %s\n" - "end-volume\n\n"; + if (child_count == 0) + goto out; + volname = volinfo->volname; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; + for (;; trav = trav->prev) { + if ((i % sub_count) == 0) { + xl = volgen_graph_add_nolink(graph, xl_type, xl_namefmt, volname, + j); + j++; } - ret = dict_get_str (dict, VOLGEN_RA_OPTION_ATIME, - &opt_atime); - if (ret) { - goto out; + if (!xl) { + ret = -1; + goto out; } - ret = dict_get_str (dict, VOLGEN_RA_OPTION_PAGECOUNT, - &opt_pagecount); - if (ret) { + if (strncmp(xl_type, "performance/readdir-ahead", + SLEN("performance/readdir-ahead")) == 0) { + ret = xlator_set_fixed_option(xl, "performance.readdir-ahead", + "on"); + if (ret) goto out; } - fprintf (file, ra_str, - volname, - "read-ahead", - opt_atime, - opt_pagecount, - subvolume); - + ret = volgen_xlator_link(xl, trav); + if (ret) + goto out; - ret = 0; + i++; + if (i == child_count) + break; + } + ret = j - start_count; out: - return ret; + return ret; } static int -__write_iocache_xlator (FILE *file, dict_t *dict, - char *subvolume) +volgen_link_bricks_from_list_tail_start(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, + char *xl_type, char *xl_namefmt, + size_t child_count, size_t sub_count, + size_t start_count) { - char *volname = NULL; - char *opt_priority = NULL; - char *opt_timeout = NULL; - char *opt_cachesize = NULL; - char *opt_minfilesize = NULL; - char *opt_maxfilesize = NULL; - int ret = -1; + xlator_t *trav = NULL; + size_t cnt = child_count; - char iocache_str[] = "volume %s-%s\n" - " type performance/io-cache\n" - "# option priority %s\n" - "# option cache-timeout %s\n" - "# option cache-size %s\n" - "# option min-file-size %s\n" - "# option max-file-size %s\n" - " subvolumes %s\n" - "end-volume\n\n"; + if (!cnt) + return -1; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + for (trav = first_of(graph); --cnt; trav = trav->next) + ; - if (dict_get (dict, "priority")) { - ret = dict_get_str (dict, "priority", &opt_priority); - gf_log("", GF_LOG_DEBUG, "Reconfiguring priority", - opt_priority); - uncomment_option (iocache_str, - (char *) "# option priority %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_PRIORITY, - &opt_priority); - if (ret) { - goto out; - } + return volgen_link_bricks(graph, volinfo, xl_type, xl_namefmt, child_count, + sub_count, start_count, trav); +} - if (dict_get (dict, "cache-timeout")) { - ret = dict_get_str (dict, "cache-timeout", &opt_timeout); - gf_log("", GF_LOG_DEBUG, "Reconfiguring cache-timeout", - opt_timeout); - uncomment_option (iocache_str, - (char *) "# option cache-timeout %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_TIMEOUT, - &opt_timeout); - if (ret) { - goto out; - } +static int +volgen_link_bricks_from_list_tail(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, char *xl_type, + char *xl_namefmt, size_t child_count, + size_t sub_count) +{ + xlator_t *trav = NULL; + size_t cnt = child_count; - if (dict_get (dict, "cache-size")) { - ret = dict_get_str (dict, "cache-size", &opt_cachesize); - gf_log("", GF_LOG_DEBUG, "Reconfiguring cache-size :%s", - opt_cachesize); - uncomment_option (iocache_str, - (char *) "# option cache-size %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_CACHESIZE, - &opt_cachesize); - if (ret) { - goto out; - } + if (!cnt) + return -1; - if (dict_get (dict, "min-file-size")) { - ret = dict_get_str (dict, "min-file-size", &opt_minfilesize); - gf_log("", GF_LOG_DEBUG, "Reconfiguring min-file-size: %s", - opt_minfilesize); - uncomment_option (iocache_str, - (char *) "# option min-file-size %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_MINFILESIZE, - &opt_minfilesize); - if (ret) { - goto out; - } + for (trav = first_of(graph); --cnt; trav = trav->next) + ; - if (dict_get (dict, "max-file-size")) { - ret = dict_get_str (dict, "max-file-size", &opt_maxfilesize); - gf_log("", GF_LOG_DEBUG, "Reconfiguring max-file-size: %s", - opt_maxfilesize); - uncomment_option (iocache_str, - (char *) "# option max-file-size %s\n"); - } - else - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_MAXFILESIZE, - &opt_maxfilesize); - if (ret) { - goto out; - } + return volgen_link_bricks(graph, volinfo, xl_type, xl_namefmt, child_count, + sub_count, 0, trav); +} - fprintf (file, iocache_str, - volname, - "io-cache", - opt_priority, - opt_timeout, - opt_cachesize, - opt_minfilesize, - opt_maxfilesize, - subvolume); +/** + * This is the build graph function for user-serviceable snapshots. + * Generates snapview-client + */ +static int +volgen_graph_build_snapview_client(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, char *volname, + dict_t *set_dict) +{ + int ret = 0; + xlator_t *prev_top = NULL; + xlator_t *prot_clnt = NULL; + xlator_t *svc = NULL; + char transt[16] = { + 0, + }; + char *svc_args[] = {"features/snapview-client", "%s-snapview-client"}; + char subvol[1024] = { + 0, + }; + char xl_id[1024] = { + 0, + }; + + prev_top = (xlator_t *)(graph->graph.first); + + snprintf(subvol, sizeof(subvol), "snapd-%s", volinfo->volname); + snprintf(xl_id, sizeof(xl_id), "%s-snapd-client", volinfo->volname); + + get_transport_type(volinfo, set_dict, transt, _gf_false); + + prot_clnt = volgen_graph_build_client(graph, volinfo, NULL, NULL, subvol, + xl_id, transt, set_dict); + if (!prot_clnt) { + ret = -1; + goto out; + } + + svc = volgen_graph_add_nolink(graph, svc_args[0], svc_args[1], volname); + if (!svc) { + ret = -1; + goto out; + } + + /** + * Ordering the below two traslators (cur_top & prot_clnt) is important + * as snapview client implementation is built on the policy that + * normal volume path goes to FIRST_CHILD and snap world operations + * goes to SECOND_CHILD + **/ + ret = volgen_xlator_link(graph->graph.first, prev_top); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_XLATOR_LINK_FAIL, + "failed to link the " + "snapview-client to distribute"); + goto out; + } + + ret = volgen_xlator_link(graph->graph.first, prot_clnt); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_XLATOR_LINK_FAIL, + "failed to link the " + "snapview-client to snapview-server"); + goto out; + } +out: + return ret; +} - ret = 0; +gf_boolean_t +_xl_is_client_decommissioned(xlator_t *xl, glusterd_volinfo_t *volinfo) +{ + int ret = 0; + gf_boolean_t decommissioned = _gf_false; + char *hostname = NULL; + char *path = NULL; + + GF_ASSERT(!strcmp(xl->type, "protocol/client")); + ret = xlator_get_fixed_option(xl, "remote-host", &hostname); + if (ret) { + GF_ASSERT(0); + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_REMOTE_HOST_GET_FAIL, + "Failed to get remote-host " + "from client %s", + xl->name); + goto out; + } + ret = xlator_get_fixed_option(xl, "remote-subvolume", &path); + if (ret) { + GF_ASSERT(0); + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_REMOTE_HOST_GET_FAIL, + "Failed to get remote-host " + "from client %s", + xl->name); + goto out; + } + + decommissioned = glusterd_is_brick_decommissioned(volinfo, hostname, path); +out: + return decommissioned; +} +gf_boolean_t +_xl_has_decommissioned_clients(xlator_t *xl, glusterd_volinfo_t *volinfo) +{ + xlator_list_t *xl_child = NULL; + gf_boolean_t decommissioned = _gf_false; + xlator_t *cxl = NULL; + + if (!xl) + goto out; + + if (!strcmp(xl->type, "protocol/client")) { + decommissioned = _xl_is_client_decommissioned(xl, volinfo); + goto out; + } + + xl_child = xl->children; + while (xl_child) { + cxl = xl_child->xlator; + /* this can go into 2 depths if the volume type + is stripe-replicate */ + decommissioned = _xl_has_decommissioned_clients(cxl, volinfo); + if (decommissioned) + break; + + xl_child = xl_child->next; + } out: - return ret; + return decommissioned; } static int -__write_qr_xlator (FILE *file, dict_t *dict, - char *subvolume) +_graph_get_decommissioned_children(xlator_t *dht, glusterd_volinfo_t *volinfo, + char **children) { - char *volname = NULL; - char *opt_priority = NULL; - char *opt_timeout = NULL; - char *opt_cachesize = NULL; - char *opt_maxfilesize = NULL; - int ret = -1; + int ret = -1; + xlator_list_t *xl_child = NULL; + xlator_t *cxl = NULL; + gf_boolean_t comma = _gf_false; + + *children = NULL; + xl_child = dht->children; + while (xl_child) { + cxl = xl_child->xlator; + if (_xl_has_decommissioned_clients(cxl, volinfo)) { + if (!*children) { + *children = GF_CALLOC(16 * GF_UNIT_KB, 1, gf_common_mt_char); + if (!*children) + goto out; + } + + if (comma) + strcat(*children, ","); + strcat(*children, cxl->name); + comma = _gf_true; + } + + xl_child = xl_child->next; + } + ret = 0; +out: + return ret; +} - const char *qr_str = "volume %s-%s\n" - " type performance/quick-read\n" - "# option priority %s\n" - "# option cache-timeout %s\n" - "# option cache-size %s\n" - "# option max-file-size %s\n" - " subvolumes %s\n" - "end-volume\n\n"; +static int +volgen_graph_build_readdir_ahead(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, + size_t child_count) +{ + int32_t clusters = 0; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + if (graph->type == GF_QUOTAD || graph->type == GF_SNAPD || + !glusterd_volinfo_get_boolean(volinfo, VKEY_PARALLEL_READDIR)) + goto out; - ret = dict_get_str (dict, VOLGEN_QR_OPTION_PRIORITY, - &opt_priority); - if (ret) { - goto out; - } + clusters = volgen_link_bricks_from_list_tail( + graph, volinfo, "performance/readdir-ahead", "%s-readdir-ahead-%d", + child_count, 1); - ret = dict_get_str (dict, VOLGEN_QR_OPTION_TIMEOUT, - &opt_timeout); - if (ret) { - goto out; - } +out: + return clusters; +} - ret = dict_get_str (dict, VOLGEN_QR_OPTION_CACHESIZE, - &opt_cachesize); +static int +volgen_graph_build_dht_cluster(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, size_t child_count, + gf_boolean_t is_quotad) +{ + int32_t clusters = 0; + int ret = -1; + char *decommissioned_children = NULL; + xlator_t *dht = NULL; + char *voltype = "cluster/distribute"; + char *name_fmt = NULL; + + /* NUFA and Switch section */ + if (dict_get_str_boolean(volinfo->dict, "cluster.nufa", 0) && + dict_get_str_boolean(volinfo->dict, "cluster.switch", 0)) { + gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "nufa and switch cannot be set together"); + ret = -1; + goto out; + } + + /* Check for NUFA volume option, and change the voltype */ + if (dict_get_str_boolean(volinfo->dict, "cluster.nufa", 0)) + voltype = "cluster/nufa"; + + /* Check for switch volume option, and change the voltype */ + if (dict_get_str_boolean(volinfo->dict, "cluster.switch", 0)) + voltype = "cluster/switch"; + + if (is_quotad) + name_fmt = "%s"; + else + name_fmt = "%s-dht"; + + clusters = volgen_link_bricks_from_list_tail( + graph, volinfo, voltype, name_fmt, child_count, child_count); + if (clusters < 0) + goto out; + + dht = first_of(graph); + ret = _graph_get_decommissioned_children(dht, volinfo, + &decommissioned_children); + if (ret) + goto out; + if (decommissioned_children) { + ret = xlator_set_fixed_option(dht, "decommissioned-bricks", + decommissioned_children); + if (ret) + goto out; + } + ret = 0; +out: + GF_FREE(decommissioned_children); + return ret; +} + +static int +volgen_graph_build_ec_clusters(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo) +{ + int i = 0; + int ret = 0; + int clusters = 0; + char *disperse_args[] = {"cluster/disperse", "%s-disperse-%d"}; + xlator_t *ec = NULL; + char option[32] = {0}; + int start_count = 0; + + clusters = volgen_link_bricks_from_list_tail_start( + graph, volinfo, disperse_args[0], disperse_args[1], + volinfo->brick_count, volinfo->disperse_count, start_count); + if (clusters < 0) + goto out; + + sprintf(option, "%d", volinfo->redundancy_count); + ec = first_of(graph); + for (i = 0; i < clusters; i++) { + ret = xlator_set_fixed_option(ec, "redundancy", option); if (ret) { - goto out; + clusters = -1; + goto out; } - ret = dict_get_str (dict, VOLGEN_QR_OPTION_MAXFILESIZE, - &opt_maxfilesize); - if (ret) { + ec = ec->next; + } +out: + return clusters; +} + +static int +set_afr_pending_xattrs_option(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, int clusters) +{ + xlator_t *xlator = NULL; + xlator_t **afr_xlators_list = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + glusterd_brickinfo_t *brick = NULL; + glusterd_brickinfo_t *ta_brick = NULL; + char *ptr = NULL; + int i = 0; + int index = -1; + int ret = 0; + char *afr_xattrs_list = NULL; + int list_size = -1; + int ta_brick_index = 0; + int subvol_index = 0; + + this = THIS; + GF_VALIDATE_OR_GOTO("glusterd", this, out); + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + if (conf->op_version < GD_OP_VERSION_3_9_0) + return ret; + + /* (brick_id x rep.count) + (rep.count-1 commas) + NULL*/ + list_size = (1024 * volinfo->replica_count) + (volinfo->replica_count - 1) + + 1; + afr_xattrs_list = GF_CALLOC(1, list_size, gf_common_mt_char); + if (!afr_xattrs_list) + goto out; + + ptr = afr_xattrs_list; + afr_xlators_list = GF_CALLOC(clusters, sizeof(xlator_t *), + gf_common_mt_xlator_t); + if (!afr_xlators_list) + goto out; + + xlator = first_of(graph); + + for (i = 0, index = clusters - 1; i < clusters; i++) { + afr_xlators_list[index--] = xlator; + xlator = xlator->next; + } + + i = 1; + index = 0; + + cds_list_for_each_entry(brick, &volinfo->bricks, brick_list) + { + if (index == clusters) + break; + strncat(ptr, brick->brick_id, strlen(brick->brick_id)); + if (i == volinfo->replica_count) { + /* add ta client xlator in afr-pending-xattrs before making entries + * for client xlators in volfile. + * ta client xlator indexes are - 2, 5, 8 depending on the index of + * subvol. e.g- For first subvol ta client xlator id is volname-ta-2 + * For pending-xattr, ta name would be + * 'volname-ta-2.{{volume-uuid}}' from GD_OP_VERSION_7_3. + */ + ta_brick_index = 0; + if (volinfo->thin_arbiter_count == 1) { + ptr[strlen(brick->brick_id)] = ','; + cds_list_for_each_entry(ta_brick, &volinfo->ta_bricks, + brick_list) + { + if (ta_brick_index == subvol_index) { + break; + } + ta_brick_index++; + } + if (conf->op_version < GD_OP_VERSION_7_3) { + strncat(ptr, ta_brick->brick_id, + strlen(ta_brick->brick_id)); + } else { + char ta_volname[PATH_MAX] = ""; + int len = snprintf(ta_volname, PATH_MAX, "%s.%s", + ta_brick->brick_id, + uuid_utoa(volinfo->volume_id)); + strncat(ptr, ta_volname, len); + } + } + + ret = xlator_set_fixed_option(afr_xlators_list[index++], + "afr-pending-xattr", afr_xattrs_list); + if (ret) goto out; + memset(afr_xattrs_list, 0, list_size); + ptr = afr_xattrs_list; + i = 1; + subvol_index++; + continue; } + ptr[strlen(brick->brick_id)] = ','; + ptr += strlen(brick->brick_id) + 1; + i++; + } - fprintf (file, qr_str, - volname, - "quick-read", - opt_priority, - opt_timeout, - opt_cachesize, - opt_maxfilesize, - subvolume); +out: + GF_FREE(afr_xattrs_list); + GF_FREE(afr_xlators_list); + return ret; +} - ret = 0; +static int +set_volfile_id_option(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + int clusters) +{ + xlator_t *xlator = NULL; + int i = 0; + int ret = -1; + glusterd_conf_t *conf = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_VALIDATE_OR_GOTO("glusterd", this, out); + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + if (conf->op_version < GD_OP_VERSION_9_0) + return 0; + xlator = first_of(graph); + + for (i = 0; i < clusters; i++) { + ret = xlator_set_fixed_option(xlator, "volume-id", + uuid_utoa(volinfo->volume_id)); + if (ret) + goto out; + + xlator = xlator->next; + } out: - return ret; + return ret; } static int -__write_statprefetch_xlator (FILE *file, dict_t *dict, - char *subvolume) +volgen_graph_build_afr_clusters(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo) { - char *volname = NULL; - int ret = -1; + int i = 0; + int ret = 0; + int clusters = 0; + char *replicate_type = "cluster/replicate"; + char *replicate_name = "%s-replicate-%d"; + xlator_t *afr = NULL; + char option[32] = {0}; + glusterd_brickinfo_t *ta_brick = NULL; + int ta_brick_index = 0; + int ta_replica_offset = 0; + int ta_brick_offset = 0; + char ta_option[4096] = { + 0, + }; + + /* In thin-arbiter case brick count and replica count remain same + * but due to additional entries of ta client xlators in the volfile, + * GD1 is manipulated to include these client xlators while linking them to + * afr/cluster entry in the volfile. + */ + if (volinfo->thin_arbiter_count == 1) { + ta_replica_offset = 1; + ta_brick_offset = volinfo->subvol_count; + } + + clusters = volgen_link_bricks_from_list_tail( + graph, volinfo, replicate_type, replicate_name, + volinfo->brick_count + ta_brick_offset, + volinfo->replica_count + ta_replica_offset); + + if (clusters < 0) + goto out; + + ret = set_afr_pending_xattrs_option(graph, volinfo, clusters); + if (ret) { + clusters = -1; + goto out; + } + + ret = set_volfile_id_option(graph, volinfo, clusters); + if (ret) { + clusters = -1; + goto out; + } + + if (!volinfo->arbiter_count && !volinfo->thin_arbiter_count) + goto out; + + afr = first_of(graph); + + if (volinfo->arbiter_count) { + sprintf(option, "%d", volinfo->arbiter_count); + for (i = 0; i < clusters; i++) { + ret = xlator_set_fixed_option(afr, "arbiter-count", option); + if (ret) { + clusters = -1; + goto out; + } + + afr = afr->next; + } + } + + if (volinfo->thin_arbiter_count == 1) { + for (i = 0; i < clusters; i++) { + ta_brick_index = 0; + cds_list_for_each_entry(ta_brick, &volinfo->ta_bricks, brick_list) + { + if (ta_brick_index == i) { + break; + } + ta_brick_index++; + } + snprintf(ta_option, sizeof(ta_option), "%s:%s", ta_brick->hostname, + ta_brick->path); + ret = xlator_set_fixed_option(afr, "thin-arbiter", ta_option); + if (ret) { + clusters = -1; + goto out; + } + afr = afr->next; + } + } +out: + return clusters; +} - const char *statprefetch_str = "volume %s-%s\n" - " type performance/stat-prefetch\n" - " subvolumes %s\n" - "end-volume\n\n"; +static int +volume_volgen_graph_build_clusters(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, + gf_boolean_t is_quotad) +{ + int clusters = 0; + int dist_count = 0; + int ret = -1; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { + if (!volinfo->dist_leaf_count) + goto out; + + if (volinfo->dist_leaf_count == 1) + goto build_distribute; + + /* All other cases, it will have one or the other cluster type */ + switch (volinfo->type) { + case GF_CLUSTER_TYPE_REPLICATE: + clusters = volgen_graph_build_afr_clusters(graph, volinfo); + if (clusters < 0) + goto out; + break; + case GF_CLUSTER_TYPE_DISPERSE: + clusters = volgen_graph_build_ec_clusters(graph, volinfo); + if (clusters < 0) goto out; - } - fprintf (file, statprefetch_str, - volname, - "stat-prefetch", - subvolume); + break; + default: + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLUME_INCONSISTENCY, + "volume inconsistency: " + "unrecognized clustering type"); + goto out; + } + +build_distribute: + dist_count = volinfo->brick_count / volinfo->dist_leaf_count; + if (!dist_count) { + ret = -1; + goto out; + } + clusters = volgen_graph_build_readdir_ahead(graph, volinfo, dist_count); + if (clusters < 0) + goto out; + + ret = volgen_graph_build_dht_cluster(graph, volinfo, dist_count, is_quotad); + if (ret) + goto out; + + ret = 0; +out: + return ret; +} - ret = 0; +static int +client_graph_set_rda_options(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict) +{ + char *rda_cache_s = NULL; + int32_t ret = 0; + uint64_t rda_cache_size = 0; + char *rda_req_s = NULL; + uint64_t rda_req_size = 0; + uint64_t new_cache_size = 0; + char new_cache_size_str[50] = { + 0, + }; + char new_req_size_str[50] = { + 0, + }; + int dist_count = 0; + + dist_count = volinfo->brick_count / volinfo->dist_leaf_count; + if (dist_count <= 1) + goto out; + + if (graph->type == GF_QUOTAD || graph->type == GF_SNAPD || + !glusterd_volinfo_get_boolean(volinfo, VKEY_PARALLEL_READDIR) || + !glusterd_volinfo_get_boolean(volinfo, VKEY_READDIR_AHEAD)) + goto out; + + /* glusterd_volinfo_get() will get the default value if nothing set + * explicitly. Hence it is important to check set_dict before checking + * glusterd_volinfo_get, so that we consider key value of the in + * progress volume set option. + */ + ret = dict_get_str_sizen(set_dict, VKEY_RDA_CACHE_LIMIT, &rda_cache_s); + if (ret < 0) { + ret = glusterd_volinfo_get(volinfo, VKEY_RDA_CACHE_LIMIT, &rda_cache_s); + if (ret < 0) + goto out; + } + ret = gf_string2bytesize_uint64(rda_cache_s, &rda_cache_size); + if (ret < 0) { + set_graph_errstr( + graph, "invalid number format in option " VKEY_RDA_CACHE_LIMIT); + goto out; + } + + ret = dict_get_str_sizen(set_dict, VKEY_RDA_REQUEST_SIZE, &rda_req_s); + if (ret < 0) { + ret = glusterd_volinfo_get(volinfo, VKEY_RDA_REQUEST_SIZE, &rda_req_s); + if (ret < 0) + goto out; + } + ret = gf_string2bytesize_uint64(rda_req_s, &rda_req_size); + if (ret < 0) { + set_graph_errstr( + graph, "invalid number format in option " VKEY_RDA_REQUEST_SIZE); + goto out; + } + + if (rda_cache_size == 0 || rda_req_size == 0) { + set_graph_errstr(graph, "Value cannot be 0"); + ret = -1; + goto out; + } + + new_cache_size = rda_cache_size / dist_count; + if (new_cache_size < rda_req_size) { + if (new_cache_size < 4 * 1024) + new_cache_size = rda_req_size = 4 * 1024; + else + rda_req_size = new_cache_size; + + snprintf(new_req_size_str, sizeof(new_req_size_str), "%" PRId64 "%s", + rda_req_size, "B"); + ret = dict_set_dynstr_with_alloc(set_dict, VKEY_RDA_REQUEST_SIZE, + new_req_size_str); + if (ret < 0) + goto out; + } + + snprintf(new_cache_size_str, sizeof(new_cache_size_str), "%" PRId64 "%s", + new_cache_size, "B"); + ret = dict_set_dynstr_with_alloc(set_dict, VKEY_RDA_CACHE_LIMIT, + new_cache_size_str); + if (ret < 0) + goto out; out: + return ret; +} + +static int +client_graph_set_perf_options(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, dict_t *set_dict) +{ + int ret = 0; + + /* + * Logic to make sure gfproxy-client gets custom performance translators + */ + ret = dict_get_str_boolean(set_dict, "gfproxy-client", 0); + if (ret == 1) { + return volgen_graph_set_options_generic( + graph, set_dict, volinfo, &gfproxy_client_perfxl_option_handler); + } + + /* + * Logic to make sure gfproxy-server gets custom performance translators + */ + ret = dict_get_str_boolean(set_dict, "gfproxy-server", 0); + if (ret == 1) { + return volgen_graph_set_options_generic( + graph, set_dict, volinfo, &gfproxy_server_perfxl_option_handler); + } + + /* + * Logic to make sure NFS doesn't have performance translators by + * default for a volume + */ + ret = client_graph_set_rda_options(graph, volinfo, set_dict); + if (ret < 0) return ret; + +#ifdef BUILD_GNFS + data_t *tmp_data = NULL; + char *volname = NULL; + + tmp_data = dict_get_sizen(set_dict, "nfs-volume-file"); + if (tmp_data) { + volname = volinfo->volname; + return volgen_graph_set_options_generic(graph, set_dict, volname, + &nfsperfxl_option_handler); + } else +#endif + return volgen_graph_set_options_generic(graph, set_dict, volinfo, + &perfxl_option_handler); +} + +static int +graph_set_generic_options(xlator_t *this, volgen_graph_t *graph, + dict_t *set_dict, char *identifier) +{ + int ret = 0; + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &loglevel_option_handler); + + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "changing %s log level" + " failed", + identifier); + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &sys_loglevel_option_handler); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "changing %s syslog " + "level failed", + identifier); + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &logger_option_handler); + + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "changing %s logger" + " failed", + identifier); + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &log_format_option_handler); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "changing %s log format" + " failed", + identifier); + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &log_buf_size_option_handler); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "Failed to change " + "log-buf-size option"); + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &log_flush_timeout_option_handler); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "Failed to change " + "log-flush-timeout option"); + + ret = volgen_graph_set_options_generic( + graph, set_dict, "client", &log_localtime_logging_option_handler); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "Failed to change " + "log-localtime-logging option"); + + ret = volgen_graph_set_options_generic(graph, set_dict, "client", + &threads_option_handler); + + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "changing %s threads failed", identifier); + + return 0; } static int -__write_iostats_xlator (FILE *file, dict_t *dict, - char *subvolume) +client_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) { - char *volname = NULL; - char *dumpfd = NULL; - char *latency = NULL; - int ret = -1; + int ret = 0; + xlator_t *xl = NULL; + char *volname = NULL; + glusterd_conf_t *conf = THIS->private; + char *tmp = NULL; + gf_boolean_t var = _gf_false; + gf_boolean_t ob = _gf_false; + int uss_enabled = -1; + xlator_t *this = THIS; + char *subvol = NULL; + size_t namelen = 0; + char *xl_id = NULL; + gf_boolean_t gfproxy_clnt = _gf_false; + + GF_ASSERT(this); + GF_ASSERT(conf); + + ret = dict_get_str_boolean(set_dict, "gfproxy-client", 0); + if (ret == -1) + goto out; + + volname = volinfo->volname; + if (ret == 0) { + ret = volgen_graph_build_clients(graph, volinfo, set_dict, param); + if (ret) + goto out; + + else + ret = volume_volgen_graph_build_clusters(graph, volinfo, _gf_false); + + if (ret == -1) + goto out; + } else { + gfproxy_clnt = _gf_true; + namelen = strlen(volinfo->volname) + SLEN("gfproxyd-") + 1; + subvol = alloca(namelen); + snprintf(subvol, namelen, "gfproxyd-%s", volinfo->volname); + + namelen = strlen(volinfo->volname) + SLEN("-gfproxy-client") + 1; + xl_id = alloca(namelen); + snprintf(xl_id, namelen, "%s-gfproxy-client", volinfo->volname); + volgen_graph_build_client(graph, volinfo, NULL, NULL, subvol, xl_id, + "tcp", set_dict); + } + + ret = dict_get_str_boolean(set_dict, "features.cloudsync", _gf_false); + if (ret == -1) + goto out; + + if (ret) { + xl = volgen_graph_add(graph, "features/cloudsync", volname); + if (!xl) { + ret = -1; + goto out; + } + } + + ret = dict_get_str_boolean(set_dict, "features.shard", _gf_false); + if (ret == -1) + goto out; + + if (ret) { + xl = volgen_graph_add(graph, "features/shard", volname); + if (!xl) { + ret = -1; + goto out; + } + } + /* a. ret will be -1 if features.ctime is not set in the volinfo->dict which + * means ctime should be loaded into the graph. + * b. ret will be 1 if features.ctime is explicitly turned on through + * volume set and in that case ctime should be loaded into the graph. + * c. ret will be 0 if features.ctime is explicitly turned off and in that + * case ctime shouldn't be loaded into the graph. + */ + ret = dict_get_str_boolean(set_dict, "features.ctime", -1); + if (conf->op_version >= GD_OP_VERSION_5_0 && ret) { + xl = volgen_graph_add(graph, "features/utime", volname); + if (!xl) { + ret = -1; + goto out; + } + } + + /* As of now snapshot volume is read-only. Read-only xlator is loaded + * in client graph so that AFR & DHT healing can be done in server. + */ + if (volinfo->is_snap_volume) { + xl = volgen_graph_add(graph, "features/read-only", volname); + if (!xl) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GRAPH_FEATURE_ADD_FAIL, + "Failed to add " + "read-only feature to the graph of %s " + "snapshot with %s origin volume", + volname, volinfo->parent_volname); + ret = -1; + goto out; + } + ret = xlator_set_fixed_option(xl, "read-only", "on"); + if (ret) + goto out; + } + + /* Check for compress volume option, and add it to the graph on client side + */ + ret = dict_get_str_boolean(set_dict, "network.compression", 0); + if (ret == -1) + goto out; + if (ret) { + xl = volgen_graph_add(graph, "features/cdc", volname); + if (!xl) { + ret = -1; + goto out; + } + ret = xlator_set_fixed_option(xl, "mode", "client"); + if (ret) + goto out; + } - const char *iostats_str = "volume %s\n" - " type debug/io-stats\n" - " option dump-fd-stats %s\n" - " option latency-measurement %s\n" - " subvolumes %s\n" - "end-volume\n\n"; + /* gfproxy needs the quiesce translator */ + if (gfproxy_clnt) { + xl = volgen_graph_add(graph, "features/quiesce", volname); + if (!xl) { + ret = -1; + goto out; + } + } - ret = dict_get_str (dict, "iostat-volname", &volname); + if (conf->op_version == GD_OP_VERSION_MIN) { + ret = glusterd_volinfo_get_boolean(volinfo, VKEY_FEATURES_QUOTA); + if (ret == -1) + goto out; if (ret) { + xl = volgen_graph_add(graph, "features/quota", volname); + if (!xl) { + ret = -1; goto out; + } + } + } + + /* Do not allow changing read-after-open option if root-squash is + enabled. + */ + ret = dict_get_str_sizen(set_dict, "performance.read-after-open", &tmp); + if (!ret) { + ret = dict_get_str_sizen(volinfo->dict, "server.root-squash", &tmp); + if (!ret) { + ob = _gf_false; + ret = gf_string2boolean(tmp, &ob); + if (!ret && ob) { + gf_msg(this->name, GF_LOG_WARNING, 0, + GD_MSG_ROOT_SQUASH_ENABLED, + "root-squash is enabled. Please turn it" + " off to change read-after-open " + "option"); + ret = -1; + goto out; + } } + } - ret = dict_get_str (dict, VOLGEN_IOS_OPTION_DUMP_FD_STATS, &dumpfd); + /* open behind causes problems when root-squash is enabled + (by allowing reads to happen even though the squashed user + does not have permissions to do so) as it fakes open to be + successful and later sends reads on anonymous fds. So when + root-squash is enabled, open-behind's option to read after + open is done is also enabled. + */ + ret = dict_get_str_sizen(set_dict, "server.root-squash", &tmp); + if (!ret) { + ret = gf_string2boolean(tmp, &var); if (ret) - goto out; - - ret = dict_get_str (dict, VOLGEN_IOS_OPTION_MEASURE_LATENCY, &latency); + goto out; + + if (var) { + ret = dict_get_str_sizen(volinfo->dict, + "performance.read-after-open", &tmp); + if (!ret) { + ret = gf_string2boolean(tmp, &ob); + /* go ahead with turning read-after-open on + even if string2boolean conversion fails, + OR if read-after-open option is turned off + */ + if (ret || !ob) + ret = dict_set_sizen_str_sizen( + set_dict, "performance.read-after-open", "yes"); + } else { + ret = dict_set_sizen_str_sizen( + set_dict, "performance.read-after-open", "yes"); + } + } else { + /* When root-squash has to be turned off, open-behind's + read-after-open option should be reset to what was + there before root-squash was turned on. If the option + cannot be found in volinfo's dict, it means that + option was not set before turning on root-squash. + */ + ob = _gf_false; + ret = dict_get_str_sizen(volinfo->dict, + "performance.read-after-open", &tmp); + if (!ret) { + ret = gf_string2boolean(tmp, &ob); + + if (!ret && ob) { + ret = dict_set_sizen_str_sizen( + set_dict, "performance.read-after-open", "yes"); + } + } + /* consider operation is failure only if read-after-open + option is enabled and could not set into set_dict + */ + if (!ob) + ret = 0; + } + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_ROOT_SQUASH_FAILED, + "setting " + "open behind option as part of root " + "squash failed"); + goto out; + } + } + + ret = dict_get_str_boolean(set_dict, "server.manage-gids", _gf_false); + if (ret != -1) { + ret = dict_set_str_sizen(set_dict, "client.send-gids", + ret ? "false" : "true"); if (ret) - goto out; + gf_msg(THIS->name, GF_LOG_WARNING, errno, GD_MSG_DICT_SET_FAILED, + "changing client" + " protocol option failed"); + } + + ret = client_graph_set_perf_options(graph, volinfo, set_dict); + if (ret) + goto out; + + uss_enabled = dict_get_str_boolean(set_dict, "features.uss", _gf_false); + if (uss_enabled == -1) + goto out; + if (uss_enabled && !volinfo->is_snap_volume) { + ret = volgen_graph_build_snapview_client(graph, volinfo, volname, + set_dict); + if (ret == -1) + goto out; + } + + /* add debug translators depending on the options */ + ret = check_and_add_debug_xl(graph, set_dict, volname, "client"); + if (ret) + return -1; + + /* if the client is part of 'gfproxyd' server, then we need to keep the + volume name as 'gfproxyd-<volname>', for better portmapper options */ + subvol = volname; + ret = dict_get_str_boolean(set_dict, "gfproxy-server", 0); + if (ret > 0) { + namelen = strlen(volinfo->volname) + SLEN("gfproxyd-") + 1; + subvol = alloca(namelen); + snprintf(subvol, namelen, "gfproxyd-%s", volname); + } + + ret = -1; + xl = volgen_graph_add_as(graph, "debug/io-stats", subvol); + if (!xl) { + goto out; + } + + ret = graph_set_generic_options(this, graph, set_dict, "client"); +out: + return ret; +} - fprintf (file, iostats_str, volname, dumpfd, latency, subvolume); +/* builds a graph for client role , with option overrides in mod_dict */ +static int +build_client_graph(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict) +{ + return build_graph_generic(graph, volinfo, mod_dict, NULL, + &client_graph_builder); +} - ret = 0; +char *gd_shd_options[] = {"!self-heal-daemon", "!heal-timeout", NULL}; -out: - return ret; +char * +gd_get_matching_option(char **options, char *option) +{ + while (*options && strcmp(*options, option)) + options++; + return *options; } static int -generate_server_volfile (glusterd_brickinfo_t *brickinfo, - dict_t *dict, - const char *filename) +bitrot_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) { - FILE *file = NULL; - char subvol[2048] = {0,}; - char *volname = NULL; - int ret = -1; - int activate_pump = 0; + xlator_t *xl = NULL; + int ret = 0; - GF_ASSERT (filename); + xl = first_of(graph); - file = fopen (filename, "w+"); - if (!file) { - gf_log ("", GF_LOG_DEBUG, - "Could not open file %s", filename); - ret = -1; - goto out; - } + if (!strcmp(vme->option, "expiry-time")) { + ret = xlator_set_fixed_option(xl, "expiry-time", vme->value); + if (ret) + return -1; + } - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + if (!strcmp(vme->option, "signer-threads")) { + ret = xlator_set_fixed_option(xl, "signer-threads", vme->value); + if (ret) + return -1; + } - /* Call functions in the same order - as you'd call if you were manually - writing a volfile top-down - */ + return ret; +} - ret = __write_posix_xlator (file, dict, brickinfo->path); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } +static int +scrubber_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + xlator_t *xl = NULL; + int ret = 0; - VOLGEN_GENERATE_VOLNAME (subvol, volname, "posix"); + xl = first_of(graph); - ret = __write_access_control_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + if (!strcmp(vme->option, "scrub-throttle")) { + ret = xlator_set_fixed_option(xl, "scrub-throttle", vme->value); + if (ret) + return -1; + } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "access-control"); + if (!strcmp(vme->option, "scrub-frequency")) { + ret = xlator_set_fixed_option(xl, "scrub-freq", vme->value); + if (ret) + return -1; + } - ret = __write_locks_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + if (!strcmp(vme->option, "scrubber")) { + if (!strcmp(vme->value, "pause")) { + ret = xlator_set_fixed_option(xl, "scrub-state", vme->value); + if (ret) + return -1; } + } - ret = dict_get_int32 (dict, "enable-pump", &activate_pump); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Pump is disabled"); - } + return ret; +} - if (activate_pump) { - gf_log ("", GF_LOG_DEBUG, - "Pump is enabled"); +static int +shd_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + int ret = 0; + struct volopt_map_entry new_vme = {0}; + char *shd_option = NULL; + + shd_option = gd_get_matching_option(gd_shd_options, vme->option); + if ((vme->option[0] == '!') && !shd_option) + goto out; + new_vme = *vme; + if (shd_option) { + new_vme.option = shd_option + 1; // option with out '!' + } + + ret = no_filter_option_handler(graph, &new_vme, param); +out: + return ret; +} - VOLGEN_GENERATE_VOLNAME (subvol, volname, "locks"); +#ifdef BUILD_GNFS +static int +nfs_option_handler(volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + static struct nfs_opt nfs_opts[] = { + /* {pattern, printf_pattern} */ + {"!rpc-auth.addr.*.allow", "rpc-auth.addr.%s.allow"}, + {"!rpc-auth.addr.*.reject", "rpc-auth.addr.%s.reject"}, + {"!rpc-auth.auth-unix.*", "rpc-auth.auth-unix.%s"}, + {"!rpc-auth.auth-null.*", "rpc-auth.auth-null.%s"}, + {"!nfs3.*.trusted-sync", "nfs3.%s.trusted-sync"}, + {"!nfs3.*.trusted-write", "nfs3.%s.trusted-write"}, + {"!nfs3.*.volume-access", "nfs3.%s.volume-access"}, + {"!rpc-auth.ports.*.insecure", "rpc-auth.ports.%s.insecure"}, + {"!nfs-disable", "nfs.%s.disable"}, + {NULL, NULL}}; + xlator_t *xl = NULL; + char *aa = NULL; + int ret = 0; + glusterd_volinfo_t *volinfo = NULL; + int keylen; + struct nfs_opt *opt = NULL; + + volinfo = param; + + if (!volinfo || (volinfo->volname[0] == '\0')) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + return 0; + } - ret = __write_replace_brick_xlator (file, dict); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + if (!vme || !(vme->option)) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL); + return 0; + } - ret = __write_pump_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + xl = first_of(graph); - VOLGEN_GENERATE_VOLNAME (subvol, volname, "pump"); - } else - VOLGEN_GENERATE_VOLNAME (subvol, volname, "locks"); + for (opt = nfs_opts; opt->pattern; opt++) { + if (!strcmp(vme->option, opt->pattern)) { + keylen = gf_asprintf(&aa, opt->printf_pattern, volinfo->volname); - ret = __write_iothreads_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + if (keylen == -1) { + return -1; + } - ret = dict_set_str (dict, "iostat-volname", brickinfo->path); - if (ret) { - goto out; + ret = xlator_set_option(xl, aa, keylen, vme->value); + GF_FREE(aa); + + if (ret) + return -1; + + goto out; } + } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "iot"); + if (!strcmp(vme->option, "!nfs3.*.export-dir")) { + keylen = gf_asprintf(&aa, "nfs3.%s.export-dir", volinfo->volname); - ret = __write_iostats_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write io-stats xlator"); - goto out; + if (keylen == -1) { + return -1; } - ret = __write_server_xlator (file, dict, brickinfo->path); + ret = gf_canonicalize_path(vme->value); if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + GF_FREE(aa); + return -1; } + ret = xlator_set_option(xl, aa, keylen, vme->value); + GF_FREE(aa); - fclose (file); - file = NULL; + if (ret) + return -1; + } else if ((strcmp(vme->voltype, "nfs/server") == 0) && + (vme->option[0] != '!')) { + ret = xlator_set_option(xl, vme->option, strlen(vme->option), + vme->value); + if (ret) + return -1; + } out: - return ret; + return 0; +} + +#endif +char * +volgen_get_shd_key(int type) +{ + char *key = NULL; + + switch (type) { + case GF_CLUSTER_TYPE_REPLICATE: + key = "cluster.self-heal-daemon"; + break; + case GF_CLUSTER_TYPE_DISPERSE: + key = "cluster.disperse-self-heal-daemon"; + break; + default: + key = NULL; + break; + } + + return key; } static int -__write_perf_xlator (char *xlator_name, FILE *file, - dict_t *dict, char *subvol) +volgen_set_shd_key_enable(dict_t *set_dict, const int type) { - int ret = 0; + int ret = 0; + + switch (type) { + case GF_CLUSTER_TYPE_REPLICATE: + ret = dict_set_sizen_str_sizen(set_dict, "cluster.self-heal-daemon", + "enable"); + break; + case GF_CLUSTER_TYPE_DISPERSE: + ret = dict_set_sizen_str_sizen( + set_dict, "cluster.disperse-self-heal-daemon", "enable"); + break; + default: + break; + } - if (strcmp (xlator_name, "write-behind") == 0) { + return ret; +} - ret = __write_wb_xlator (file, dict, subvol); +static gf_boolean_t +volgen_is_shd_compatible_xl(char *xl_type) +{ + char *shd_xls[] = {"cluster/replicate", "cluster/disperse", NULL}; + if (gf_get_index_by_elem(shd_xls, xl_type) != -1) + return _gf_true; - } else if (strcmp (xlator_name, "read-ahead") == 0) { + return _gf_false; +} - ret = __write_ra_xlator (file, dict, subvol); +static int +volgen_graph_set_iam_shd(volgen_graph_t *graph) +{ + xlator_t *trav; + int ret = 0; - } else if (strcmp (xlator_name, "io-cache") == 0) { + for (trav = first_of(graph); trav; trav = trav->next) { + if (!volgen_is_shd_compatible_xl(trav->type)) + continue; - ret = __write_iocache_xlator (file, dict, subvol); + ret = xlator_set_fixed_option(trav, "iam-self-heal-daemon", "yes"); + if (ret) + break; + } + return ret; +} - } else if (strcmp (xlator_name, "quick-read") == 0) { +static int +prepare_shd_volume_options(glusterd_volinfo_t *volinfo, dict_t *mod_dict, + dict_t *set_dict) +{ + int ret = 0; + + ret = volgen_set_shd_key_enable(set_dict, volinfo->type); + if (ret) + goto out; + + ret = dict_set_uint32(set_dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; + } + + dict_copy(volinfo->dict, set_dict); + if (mod_dict) + dict_copy(mod_dict, set_dict); +out: + return ret; +} - ret = __write_qr_xlator (file, dict, subvol); +static int +build_afr_ec_clusters(volgen_graph_t *graph, glusterd_volinfo_t *volinfo) +{ + int clusters = -1; + switch (volinfo->type) { + case GF_CLUSTER_TYPE_REPLICATE: + clusters = volgen_graph_build_afr_clusters(graph, volinfo); + break; + + case GF_CLUSTER_TYPE_DISPERSE: + clusters = volgen_graph_build_ec_clusters(graph, volinfo); + break; + } + return clusters; +} - } else if (strcmp (xlator_name, "stat-prefetch") == 0) { +static int +build_shd_clusters(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict) +{ + int ret = 0; + int clusters = -1; - ret = __write_statprefetch_xlator (file, dict, subvol); + ret = volgen_graph_build_clients(graph, volinfo, set_dict, NULL); + if (ret) + goto out; + clusters = build_afr_ec_clusters(graph, volinfo); - } +out: + return clusters; +} - return ret; +gf_boolean_t +gd_is_self_heal_enabled(glusterd_volinfo_t *volinfo, dict_t *dict) +{ + char *shd_key = NULL; + gf_boolean_t shd_enabled = _gf_false; + + GF_VALIDATE_OR_GOTO("glusterd", volinfo, out); + switch (volinfo->type) { + case GF_CLUSTER_TYPE_REPLICATE: + case GF_CLUSTER_TYPE_DISPERSE: + shd_key = volgen_get_shd_key(volinfo->type); + shd_enabled = dict_get_str_boolean(dict, shd_key, _gf_true); + break; + default: + break; + } +out: + return shd_enabled; } -static int -add_perf_xlator_list_item (dict_t *dict, char **perf_xlator_list, - char *xlator_name, int *idx) +build_rebalance_volfile(glusterd_volinfo_t *volinfo, char *filepath, + dict_t *mod_dict) { - int ret = 0; + volgen_graph_t graph = { + 0, + }; + xlator_t *xl = NULL; + int ret = -1; + xlator_t *this = NULL; + dict_t *set_dict = NULL; + + this = THIS; + + graph.type = GF_REBALANCED; + + if (volinfo->brick_count <= volinfo->dist_leaf_count) { + /* + * Volume is not a distribute volume or + * contains only 1 brick, no need to create + * the volfiles. + */ + return 0; + } - ret = dict_get_str_boolean (dict, xlator_name, 1); - switch (ret) { - case -1: - goto out; - case 1: - gf_log ("", GF_LOG_DEBUG, - "%s is enabled", xlator_name); - perf_xlator_list[*idx] = gf_strdup (xlator_name); - if (!perf_xlator_list[*idx]) { - gf_log ("", GF_LOG_ERROR, "Out of memory"); - - return -1; - } + set_dict = dict_copy_with_ref(volinfo->dict, NULL); + if (!set_dict) + return -1; - (*idx)++; + if (mod_dict) { + dict_copy(mod_dict, set_dict); + /* XXX dict_copy swallows errors */ + } - break; - case 0: - gf_log ("", GF_LOG_DEBUG, "%s option is disabled", xlator_name); - break; - default: - GF_ASSERT (!"Biohazard!"); - } + /* Rebalance is always a trusted client*/ + ret = dict_set_uint32(set_dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret) + return -1; - ret = 0; + ret = volgen_graph_build_clients(&graph, volinfo, set_dict, NULL); + if (ret) + goto out; + + ret = volume_volgen_graph_build_clusters(&graph, volinfo, _gf_false); + if (ret) + goto out; + + xl = volgen_graph_add_as(&graph, "debug/io-stats", volinfo->volname); + if (!xl) { + ret = -1; + goto out; + } + + ret = graph_set_generic_options(this, &graph, set_dict, "rebalance-daemon"); + if (ret) + goto out; + + ret = volgen_graph_set_options_generic(&graph, set_dict, volinfo, + basic_option_handler); + + if (!ret) + ret = volgen_write_volfile(&graph, filepath); out: - return ret; + volgen_graph_free(&graph); + + dict_unref(set_dict); + + return ret; } static int -generate_perf_xlator_list (dict_t *dict, char *perf_xlator_list[]) +build_shd_volume_graph(xlator_t *this, volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, dict_t *mod_dict, + dict_t *set_dict, gf_boolean_t graph_check) { - int i = 0; - int ret = 0; + volgen_graph_t cgraph = {0}; + int ret = 0; + int clusters = -1; - GF_ASSERT (dict); + if (!glusterd_is_shd_compatible_volume(volinfo)) + goto out; - ret = add_perf_xlator_list_item (dict, perf_xlator_list, - "write-behind", &i); - if (ret == -1) - goto out; + ret = prepare_shd_volume_options(volinfo, mod_dict, set_dict); + if (ret) + goto out; - ret = add_perf_xlator_list_item (dict, perf_xlator_list, - "read-ahead", &i); - if (ret == -1) - goto out; + clusters = build_shd_clusters(&cgraph, volinfo, set_dict); + if (clusters < 0) { + ret = -1; + goto out; + } - ret = add_perf_xlator_list_item (dict, perf_xlator_list, - "io-cache", &i); - if (ret == -1) - goto out; + ret = volgen_graph_set_options_generic(&cgraph, set_dict, volinfo, + shd_option_handler); + if (ret) + goto out; - ret = add_perf_xlator_list_item (dict, perf_xlator_list, - "quick-read", &i); - if (ret == -1) - goto out; + ret = volgen_graph_set_iam_shd(&cgraph); + if (ret) + goto out; - ret = add_perf_xlator_list_item (dict, perf_xlator_list, - "stat-prefetch", &i); - if (ret == -1) - goto out; + ret = volgen_graph_merge_sub(graph, &cgraph, clusters); + if (ret) + goto out; + ret = graph_set_generic_options(this, graph, set_dict, "self-heal daemon"); out: - return ret; + return ret; } +int +build_shd_graph(glusterd_volinfo_t *volinfo, volgen_graph_t *graph, + dict_t *mod_dict) +{ + xlator_t *this = NULL; + dict_t *set_dict = NULL; + int ret = 0; + xlator_t *iostxl = NULL; + gf_boolean_t graph_check = _gf_false; + + this = THIS; + + set_dict = dict_new(); + if (!set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + ret = -ENOMEM; + goto out; + } + + if (mod_dict) + graph_check = dict_get_str_boolean(mod_dict, "graph-check", 0); + iostxl = volgen_graph_add_as(graph, "debug/io-stats", volinfo->volname); + if (!iostxl) { + ret = -1; + goto out; + } + + ret = build_shd_volume_graph(this, graph, volinfo, mod_dict, set_dict, + graph_check); + +out: + if (set_dict) + dict_unref(set_dict); + return ret; +} + +#ifdef BUILD_GNFS + static int -destroy_perf_xlator_list (char *perf_xlator_list[]) +volgen_graph_set_iam_nfsd(const volgen_graph_t *graph) { - int i = 0; + xlator_t *trav; + int ret = 0; - while (perf_xlator_list[i]) { - GF_FREE (perf_xlator_list[i]); - i++; - } + for (trav = first_of((volgen_graph_t *)graph); trav; trav = trav->next) { + if (strcmp(trav->type, "cluster/replicate") != 0) + continue; - return 0; + ret = xlator_set_fixed_option(trav, "iam-nfs-daemon", "yes"); + if (ret) + break; + } + return ret; } -static int -write_perf_xlators (glusterd_volinfo_t *volinfo, FILE *file, - int32_t dist_count, int32_t replicate_count, - int32_t stripe_count, char *last_xlator) +/* builds a graph for nfs server role, with option overrides in mod_dict */ +int +build_nfs_graph(volgen_graph_t *graph, dict_t *mod_dict) { - char *perf_xlator_list[256] = {0,}; - char subvol[2048] = {0,}; - int i = 0; - int last_idx = 0; - int ret = 0; - char *volname = NULL; - dict_t *dict = NULL; + volgen_graph_t cgraph = { + 0, + }; + glusterd_volinfo_t *voliter = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + dict_t *set_dict = NULL; + xlator_t *nfsxl = NULL; + char *skey = NULL; + int ret = 0; + char nfs_xprt[16] = { + 0, + }; + char *volname = NULL; + data_t *data = NULL; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + set_dict = dict_new(); + if (!set_dict) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Out of memory"); + return -1; + } + + nfsxl = volgen_graph_add_as(graph, "nfs/server", "nfs-server"); + if (!nfsxl) { + ret = -1; + goto out; + } + ret = xlator_set_fixed_option(nfsxl, "nfs.dynamic-volumes", "on"); + if (ret) + goto out; + + ret = xlator_set_fixed_option(nfsxl, "nfs.nlm", "on"); + if (ret) + goto out; + + ret = xlator_set_fixed_option(nfsxl, "nfs.drc", "off"); + if (ret) + goto out; + + cds_list_for_each_entry(voliter, &priv->volumes, vol_list) + { + if (voliter->status != GLUSTERD_STATUS_STARTED) + continue; + + if (dict_get_str_boolean(voliter->dict, NFS_DISABLE_MAP_KEY, 0)) + continue; + + ret = gf_asprintf(&skey, "rpc-auth.addr.%s.allow", voliter->volname); + if (ret == -1) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Out of memory"); + goto out; + } + ret = xlator_set_option(nfsxl, skey, ret, "*"); + GF_FREE(skey); + if (ret) + goto out; - dict = volinfo->dict; - volname = volinfo->volname; + ret = gf_asprintf(&skey, "nfs3.%s.volume-id", voliter->volname); + if (ret == -1) { + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_NO_MEMORY, + "Out of memory"); + goto out; + } + ret = xlator_set_option(nfsxl, skey, ret, + uuid_utoa(voliter->volume_id)); + GF_FREE(skey); + if (ret) + goto out; + + /* If both RDMA and TCP are the transport_type, use TCP for NFS + * client protocols, because tcp,rdma volume can be created in + * servers which does not have rdma supported hardware + * The transport type specified here is client transport type + * which is used for communication between gluster-nfs and brick + * processes. + * User can specify client transport for tcp,rdma volume using + * nfs.transport-type, if it is not set by user default + * one will be tcp. + */ + memset(&cgraph, 0, sizeof(cgraph)); + if (mod_dict) + get_transport_type(voliter, mod_dict, nfs_xprt, _gf_true); + else + get_transport_type(voliter, voliter->dict, nfs_xprt, _gf_true); - ret = generate_perf_xlator_list ( - dict, perf_xlator_list); + ret = dict_set_sizen_str_sizen(set_dict, "performance.stat-prefetch", + "off"); if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate perf xlator list"); - goto out; + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=performance.stat-prefetch", NULL); + goto out; } - while (perf_xlator_list[i]) { - i++; + ret = dict_set_sizen_str_sizen(set_dict, + "performance.client-io-threads", "off"); + if (ret) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=performance.client-io-threads", NULL); + goto out; } - if (i == 0) { - gf_log ("", GF_LOG_DEBUG, - "No perf xlators enabled"); - ret = 0; - goto out; + ret = dict_set_str_sizen(set_dict, "client-transport-type", nfs_xprt); + if (ret) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=client-transport-type", NULL); + goto out; } - i = 0; - - if (dist_count > 1) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "dht"); - ret = __write_perf_xlator (perf_xlator_list[i], file, - dict, subvol); - i++; + ret = dict_set_uint32(set_dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; } - else if (replicate_count > 1) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "replicate-0"); - ret = __write_perf_xlator (perf_xlator_list[i], file, - dict, subvol); - i++; + ret = dict_set_sizen_str_sizen(set_dict, "nfs-volume-file", "yes"); + if (ret) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=nfs-volume-file", NULL); + goto out; } - else if (stripe_count > 1) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "stripe-0"); - ret = __write_perf_xlator (perf_xlator_list[i], file, - dict, subvol); - i++; + if (mod_dict && (data = dict_get_sizen(mod_dict, "volume-name"))) { + volname = data->data; + if (strcmp(volname, voliter->volname) == 0) + dict_copy(mod_dict, set_dict); } - else { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "client-0"); - ret = __write_perf_xlator (perf_xlator_list[i], file, - dict, subvol); - i++; - } - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + ret = build_client_graph(&cgraph, voliter, set_dict); + if (ret) + goto out; + + if (mod_dict) { + dict_copy(mod_dict, set_dict); + ret = volgen_graph_set_options_generic(&cgraph, set_dict, voliter, + basic_option_handler); + } else { + ret = volgen_graph_set_options_generic( + &cgraph, voliter->dict, voliter, basic_option_handler); } - while (perf_xlator_list[i]) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, perf_xlator_list[i-1]); - ret = __write_perf_xlator (perf_xlator_list[i], file, - dict, subvol); - i++; + if (ret) + goto out; - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + ret = volgen_graph_set_iam_nfsd(&cgraph); + if (ret) + goto out; + + ret = volgen_graph_merge_sub(graph, &cgraph, 1); + if (ret) + goto out; + ret = dict_reset(set_dict); + if (ret) + goto out; + } + + cds_list_for_each_entry(voliter, &priv->volumes, vol_list) + { + if (mod_dict) { + ret = volgen_graph_set_options_generic(graph, mod_dict, voliter, + nfs_option_handler); + } else { + ret = volgen_graph_set_options_generic(graph, voliter->dict, + voliter, nfs_option_handler); } - if (i >= 1) { - last_idx = i - 1; + if (ret) + gf_msg("glusterd", GF_LOG_WARNING, 0, GD_MSG_GRAPH_SET_OPT_FAIL, + "Could not set " + "vol-options for the volume %s", + voliter->volname); + } - if (perf_xlator_list[last_idx] && last_idx >= 0) { - VOLGEN_GENERATE_VOLNAME (last_xlator, volname, - perf_xlator_list[last_idx]); - gf_log ("", GF_LOG_DEBUG, - "last xlator copied to %s", last_xlator); - } - } +out: + gf_msg_debug("glusterd", 0, "Returning %d", ret); + dict_unref(set_dict); + return ret; +} +#endif +/**************************** + * + * Volume generation interface + * + ****************************/ + +static void +get_brick_filepath(char *filename, glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, char *prefix) +{ + char path[PATH_MAX] = { + 0, + }; + char brick[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + int32_t len = 0; + + priv = THIS->private; + + GLUSTERD_REMOVE_SLASH_FROM_PATH(brickinfo->path, brick); + GLUSTERD_GET_VOLUME_DIR(path, volinfo, priv); + + if (prefix) + len = snprintf(filename, PATH_MAX, "%s/%s.%s.%s.%s.vol", path, + volinfo->volname, prefix, brickinfo->hostname, brick); + else + len = snprintf(filename, PATH_MAX, "%s/%s.%s.%s.vol", path, + volinfo->volname, brickinfo->hostname, brick); + if ((len < 0) || (len >= PATH_MAX)) { + filename[0] = 0; + } +} + +gf_boolean_t +glusterd_is_valid_volfpath(char *volname, char *brick) +{ + char volfpath[PATH_MAX] = { + 0, + }; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_volinfo_t *volinfo = NULL; + int32_t ret = 0; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + + ret = glusterd_brickinfo_new_from_brick(brick, &brickinfo, _gf_false, NULL); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICKINFO_CREATE_FAIL, + "Failed to create brickinfo" + " for brick %s", + brick); + ret = 0; + goto out; + } + ret = glusterd_volinfo_new(&volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOLINFO_STORE_FAIL, + "Failed to create volinfo"); + ret = 0; + goto out; + } + (void)snprintf(volinfo->volname, sizeof(volinfo->volname), "%s", volname); + get_brick_filepath(volfpath, volinfo, brickinfo, NULL); + + ret = ((strlen(volfpath) < PATH_MAX) && + strlen(strrchr(volfpath, '/')) < _POSIX_PATH_MAX); out: - destroy_perf_xlator_list (perf_xlator_list); - return ret; + if (brickinfo) + glusterd_brickinfo_delete(brickinfo); + if (volinfo) + glusterd_volinfo_unref(volinfo); + return ret; +} +int +glusterd_build_gfproxyd_volfile(glusterd_volinfo_t *volinfo, char *filename) +{ + volgen_graph_t graph = { + 0, + }; + int ret = -1; + + ret = build_graph_generic(&graph, volinfo, NULL, NULL, + &gfproxy_server_graph_builder); + if (ret == 0) + ret = volgen_write_volfile(&graph, filename); + + volgen_graph_free(&graph); + + return ret; +} + +int +glusterd_generate_gfproxyd_volfile(glusterd_volinfo_t *volinfo) +{ + char filename[PATH_MAX] = { + 0, + }; + int ret = -1; + + GF_ASSERT(volinfo); + + glusterd_svc_build_gfproxyd_volfile_path(volinfo, filename, PATH_MAX - 1); + + ret = glusterd_build_gfproxyd_volfile(volinfo, filename); + + return ret; } static int -generate_client_volfile (glusterd_volinfo_t *volinfo, char *filename) +glusterd_generate_brick_volfile(glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + dict_t *mod_dict, void *data) { - FILE *file = NULL; - dict_t *dict = NULL; - char *volname = NULL; - glusterd_brickinfo_t *brick = NULL; - char last_xlator[1024] = {0,}; - char subvol[2048] = {0,}; - int32_t replicate_count = 0; - int32_t stripe_count = 0; - int32_t dist_count = 0; - int32_t num_bricks = 0; - int subvol_count = 0; - int count = 0; - int i = 0; - int ret = -1; + volgen_graph_t graph = { + 0, + }; + char filename[PATH_MAX] = { + 0, + }; + int ret = -1; - GF_ASSERT (filename); + GF_ASSERT(volinfo); + GF_ASSERT(brickinfo); - volname = volinfo->volname; - dict = volinfo->dict; - - list_for_each_entry (brick, &volinfo->bricks, brick_list) - num_bricks++; - - if (GF_CLUSTER_TYPE_REPLICATE == volinfo->type) { - if (volinfo->brick_count <= volinfo->sub_count) { - gf_log ("", GF_LOG_DEBUG, - "Volfile is plain replicated"); - replicate_count = volinfo->sub_count; - dist_count = num_bricks / replicate_count; - if (!dist_count) { - replicate_count = num_bricks; - dist_count = num_bricks / replicate_count; - } - } else { - gf_log ("", GF_LOG_DEBUG, - "Volfile is distributed-replicated"); - replicate_count = volinfo->sub_count; - dist_count = num_bricks / replicate_count; - } + get_brick_filepath(filename, volinfo, brickinfo, NULL); - } else if (GF_CLUSTER_TYPE_STRIPE == volinfo->type) { - if (volinfo->brick_count == volinfo->sub_count) { - gf_log ("", GF_LOG_DEBUG, - "Volfile is plain striped"); - stripe_count = volinfo->sub_count; - dist_count = num_bricks / stripe_count; - } else { - gf_log ("", GF_LOG_DEBUG, - "Volfile is distributed-striped"); - stripe_count = volinfo->sub_count; - dist_count = num_bricks / stripe_count; - } - } else { - gf_log ("", GF_LOG_DEBUG, - "Volfile is plain distributed"); - dist_count = num_bricks; - } + ret = build_server_graph(&graph, volinfo, mod_dict, brickinfo); + if (!ret) + ret = volgen_write_volfile(&graph, filename); + volgen_graph_free(&graph); - file = fopen (filename, "w+"); - if (!file) { - gf_log ("", GF_LOG_DEBUG, - "Could not open file %s", filename); - ret = -1; - goto out; - } + return ret; +} - /* Call functions in the same order - as you'd call if you were manually - writing a volfile top-down - */ +int +build_quotad_graph(volgen_graph_t *graph, dict_t *mod_dict) +{ + volgen_graph_t cgraph = {0}; + glusterd_volinfo_t *voliter = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + dict_t *set_dict = NULL; + int ret = 0; + xlator_t *quotad_xl = NULL; + char *skey = NULL; + + this = THIS; + GF_ASSERT(this); + + priv = this->private; + GF_ASSERT(priv); + + graph->type = GF_QUOTAD; + + set_dict = dict_new(); + if (!set_dict) { + ret = -ENOMEM; + goto out; + } + + quotad_xl = volgen_graph_add_as(graph, "features/quotad", "quotad"); + if (!quotad_xl) { + ret = -1; + goto out; + } + + cds_list_for_each_entry(voliter, &priv->volumes, vol_list) + { + if (voliter->status != GLUSTERD_STATUS_STARTED) + continue; + + if (1 != glusterd_is_volume_quota_enabled(voliter)) + continue; + + ret = dict_set_uint32(set_dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; + } - count = 0; + dict_copy(voliter->dict, set_dict); + if (mod_dict) + dict_copy(mod_dict, set_dict); - list_for_each_entry (brick, &volinfo->bricks, brick_list) { + ret = gf_asprintf(&skey, "%s.volume-id", voliter->volname); + if (ret == -1) { + gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Out of memory"); + goto out; + } + ret = xlator_set_option(quotad_xl, skey, ret, voliter->volname); + GF_FREE(skey); + if (ret) + goto out; - ret = __write_client_xlator (file, dict, brick->path, - brick->hostname, count, - last_xlator); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + memset(&cgraph, 0, sizeof(cgraph)); + ret = volgen_graph_build_clients(&cgraph, voliter, set_dict, NULL); + if (ret) + goto out; - count++; + ret = volume_volgen_graph_build_clusters(&cgraph, voliter, _gf_true); + if (ret) { + ret = -1; + goto out; } - if (stripe_count && replicate_count) { - gf_log ("", GF_LOG_DEBUG, - "Striped Replicate config not allowed"); - ret = -1; - goto out; + if (mod_dict) { + dict_copy(mod_dict, set_dict); + ret = volgen_graph_set_options_generic(&cgraph, set_dict, voliter, + basic_option_handler); + } else { + ret = volgen_graph_set_options_generic( + &cgraph, voliter->dict, voliter, basic_option_handler); } + if (ret) + goto out; - if (replicate_count > 1) { - subvol_count = 0; - for (i = 0; i < dist_count; i++) { + ret = volgen_graph_merge_sub(graph, &cgraph, 1); + if (ret) + goto out; - VOLGEN_GENERATE_VOLNAME (subvol, volname, "client"); + ret = dict_reset(set_dict); + if (ret) + goto out; + } - ret = __write_replicate_xlator (file, dict, subvol, - replicate_count, - subvol_count, - i, - last_xlator); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Count not write xlator"); - goto out; - } +out: + if (set_dict) + dict_unref(set_dict); + return ret; +} - subvol_count += replicate_count; +static void +get_vol_tstamp_file(char *filename, glusterd_volinfo_t *volinfo) +{ + glusterd_conf_t *priv = NULL; + + priv = THIS->private; + + GLUSTERD_GET_VOLUME_DIR(filename, volinfo, priv); + strncat(filename, "/marker.tstamp", PATH_MAX - strlen(filename) - 1); +} +static void +get_parent_vol_tstamp_file(char *filename, glusterd_volinfo_t *volinfo) +{ + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + int32_t len = 0; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + len = snprintf(filename, PATH_MAX, "%s/vols/%s/marker.tstamp", + priv->workdir, volinfo->parent_volname); + if ((len < 0) || (len >= PATH_MAX)) { + filename[0] = 0; + } +} + +int +generate_brick_volfiles(glusterd_volinfo_t *volinfo) +{ + char tstamp_file[PATH_MAX] = { + 0, + }; + char parent_tstamp_file[PATH_MAX] = { + 0, + }; + int ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + + ret = glusterd_volinfo_get_boolean(volinfo, VKEY_MARKER_XTIME); + if (ret == -1) + return -1; + + assign_brick_groups(volinfo); + get_vol_tstamp_file(tstamp_file, volinfo); + + if (ret) { + ret = open(tstamp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (ret == -1 && errno == EEXIST) { + gf_msg_debug(this->name, 0, "timestamp file exist"); + ret = -2; + } + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "failed to create " + "%s", + tstamp_file); + return -1; + } + if (ret >= 0) { + sys_close(ret); + /* If snap_volume, retain timestamp for marker.tstamp + * from parent. Geo-replication depends on mtime of + * 'marker.tstamp' to decide the volume-mark, i.e., + * geo-rep start time just after session is created. + */ + if (volinfo->is_snap_volume) { + get_parent_vol_tstamp_file(parent_tstamp_file, volinfo); + ret = gf_set_timestamp(parent_tstamp_file, tstamp_file); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_TSTAMP_SET_FAIL, + "Unable to set atime and mtime" + " of %s as of %s", + tstamp_file, parent_tstamp_file); + goto out; } + } + } + } else { + ret = sys_unlink(tstamp_file); + if (ret == -1 && errno == ENOENT) + ret = 0; + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "failed to unlink " + "%s", + tstamp_file); + return -1; } + } - if (stripe_count > 1) { - subvol_count = 0; - for (i = 0; i < dist_count; i++) { + ret = glusterd_volume_brick_for_each(volinfo, NULL, + glusterd_generate_brick_volfile); + if (ret) + goto out; - VOLGEN_GENERATE_VOLNAME (subvol, volname, "client"); + ret = 0; - ret = __write_stripe_xlator (file, dict, subvol, - stripe_count, - subvol_count, - i, - last_xlator); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Count not write xlator"); - goto out; - } +out: + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; +} - subvol_count += stripe_count; - } +static int +generate_single_transport_client_volfile(glusterd_volinfo_t *volinfo, + char *filepath, dict_t *dict) +{ + volgen_graph_t graph = { + 0, + }; + int ret = -1; - } + ret = build_client_graph(&graph, volinfo, dict); + if (!ret) + ret = volgen_write_volfile(&graph, filepath); - if (dist_count > 1) { - if (replicate_count) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, - "replicate"); - } else if (stripe_count) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, - "stripe"); - } else { - VOLGEN_GENERATE_VOLNAME (subvol, volname, - "client"); - } + volgen_graph_free(&graph); + return ret; +} - ret = __write_distribute_xlator (file, - dict, - subvol, - dist_count, - last_xlator); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Count not write xlator"); - goto out; +int +glusterd_generate_client_per_brick_volfile(glusterd_volinfo_t *volinfo) +{ + char filepath[PATH_MAX] = { + 0, + }; + glusterd_brickinfo_t *brick = NULL; + volgen_graph_t graph = { + 0, + }; + dict_t *dict = NULL; + xlator_t *xl = NULL; + int ret = -1; + char *ssl_str = NULL; + gf_boolean_t ssl_bool = _gf_false; + xlator_t *this = THIS; + GF_ASSERT(this); + + dict = dict_new(); + if (!dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + goto out; + } + + ret = dict_set_uint32(dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto free_dict; + } + + if (dict_get_str_sizen(volinfo->dict, "client.ssl", &ssl_str) == 0) { + if (gf_string2boolean(ssl_str, &ssl_bool) == 0) { + if (ssl_bool) { + if (dict_set_dynstr_with_alloc(dict, "client.ssl", "on") != 0) { + ret = -1; + goto free_dict; } + } + } else { + ret = -1; + goto free_dict; } + } + + cds_list_for_each_entry(brick, &volinfo->bricks, brick_list) + { + xl = volgen_graph_build_client(&graph, volinfo, brick->hostname, NULL, + brick->path, brick->brick_id, "tcp", + dict); + if (!xl) { + ret = -1; + goto out; + } + + get_brick_filepath(filepath, volinfo, brick, "client"); + ret = volgen_write_volfile(&graph, filepath); + if (ret < 0) + goto out; + volgen_graph_free(&graph); + memset(&graph, 0, sizeof(graph)); + } - ret = write_perf_xlators (volinfo, file, dist_count, - replicate_count, stripe_count, - last_xlator); + ret = 0; +out: + if (ret) + volgen_graph_free(&graph); + +free_dict: + + if (dict) + dict_unref(dict); + + return ret; +} + +static void +enumerate_transport_reqs(gf_transport_type type, char **types) +{ + switch (type) { + case GF_TRANSPORT_TCP: + types[0] = "tcp"; + break; + case GF_TRANSPORT_RDMA: + types[0] = "rdma"; + break; + case GF_TRANSPORT_BOTH_TCP_RDMA: + types[0] = "tcp"; + types[1] = "rdma"; + break; + } +} + +int +generate_dummy_client_volfiles(glusterd_volinfo_t *volinfo) +{ + int i = 0; + int ret = -1; + char filepath[PATH_MAX] = { + 0, + }; + char *types[] = {NULL, NULL, NULL}; + dict_t *dict = NULL; + xlator_t *this = NULL; + gf_transport_type type = GF_TRANSPORT_TCP; + + this = THIS; + + enumerate_transport_reqs(volinfo->transport_type, types); + dict = dict_new(); + if (!dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + goto out; + } + for (i = 0; types[i]; i++) { + ret = dict_set_str(dict, "client-transport-type", types[i]); if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write performance xlators"); - goto out; + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=client-transport-type", NULL); + goto out; } + type = transport_str_to_type(types[i]); - ret = dict_set_str (dict, "iostat-volname", volname); + ret = dict_set_uint32(dict, "trusted-client", GF_CLIENT_OTHER); if (ret) { - goto out; + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; } - ret = __write_iostats_xlator (file, - dict, - last_xlator); + ret = glusterd_get_dummy_client_filepath(filepath, volinfo, type); if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write io-stats xlator"); - goto out; + gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, + "Received invalid transport-type."); + goto out; } + ret = generate_single_transport_client_volfile(volinfo, filepath, dict); + if (ret) + goto out; + } + out: - if (file) - fclose (file); - file = NULL; + if (dict) + dict_unref(dict); - return ret; + gf_msg_trace("glusterd", 0, "Returning %d", ret); + return ret; } -static char * -get_brick_filename (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +int +generate_client_volfiles(glusterd_volinfo_t *volinfo, + glusterd_client_type_t client_type) { - char path[PATH_MAX] = {0,}; - char *ret = NULL; - char brick[PATH_MAX] = {0,}; - char *filename = NULL; + int i = 0; + int ret = -1; + char filepath[PATH_MAX] = { + 0, + }; + char *volname = NULL; + char *types[] = {NULL, NULL, NULL}; + dict_t *dict = NULL; + xlator_t *this = NULL; + gf_transport_type type = GF_TRANSPORT_TCP; + + this = THIS; + + volname = volinfo->is_snap_volume ? volinfo->parent_volname + : volinfo->volname; + + if (volname && !strcmp(volname, GLUSTER_SHARED_STORAGE) && + client_type != GF_CLIENT_TRUSTED) { + /* + * shared storage volume cannot be mounted from non trusted + * nodes. So we are not creating volfiles for non-trusted + * clients for shared volumes as well as snapshot of shared + * volumes. + */ - filename = GF_CALLOC (1, PATH_MAX, gf_gld_mt_char); - if (!filename) - goto out; + ret = 0; + gf_msg_debug("glusterd", 0, + "Skipping the non-trusted volfile" + "creation for shared storage volume. Volume %s", + volname); + goto out; + } + + enumerate_transport_reqs(volinfo->transport_type, types); + dict = dict_new(); + if (!dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + goto out; + } + for (i = 0; types[i]; i++) { + ret = dict_set_str(dict, "client-transport-type", types[i]); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=client-transport-type", NULL); + goto out; + } + type = transport_str_to_type(types[i]); + + ret = dict_set_uint32(dict, "trusted-client", client_type); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; + } + + if (client_type == GF_CLIENT_TRUSTED) { + ret = glusterd_get_trusted_client_filepath(filepath, volinfo, type); + } else if (client_type == GF_CLIENT_TRUSTED_PROXY) { + glusterd_get_gfproxy_client_volfile(volinfo, filepath, PATH_MAX); + ret = dict_set_int32_sizen(dict, "gfproxy-client", 1); + } else { + ret = glusterd_get_client_filepath(filepath, volinfo, type); + } + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, + "Received invalid transport-type"); + goto out; + } + + ret = generate_single_transport_client_volfile(volinfo, filepath, dict); + if (ret) + goto out; + } - GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick); - VOLGEN_GET_VOLUME_DIR (path, volinfo); + /* Generate volfile for rebalance process */ + glusterd_get_rebalance_volfile(volinfo, filepath, PATH_MAX); + ret = build_rebalance_volfile(volinfo, filepath, dict); - snprintf (filename, PATH_MAX, "%s/%s.%s.%s.vol", - path, volinfo->volname, - brickinfo->hostname, - brick); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL, + "Failed to create rebalance volfile for %s", volinfo->volname); + goto out; + } - ret = filename; out: - return ret; + if (dict) + dict_unref(dict); + + gf_msg_trace("glusterd", 0, "Returning %d", ret); + return ret; } -char * -glusterd_get_nfs_filepath () +int +glusterd_snapdsvc_generate_volfile(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo) { - char path[PATH_MAX] = {0,}; - char *ret = NULL; - char *filepath = NULL; + xlator_t *xl = NULL; + char *username = NULL; + char *passwd = NULL; + int ret = 0; + char key[PATH_MAX] = { + 0, + }; + dict_t *set_dict = NULL; + char *loglevel = NULL; + char *xlator = NULL; + char *ssl_str = NULL; + gf_boolean_t ssl_bool = _gf_false; + + set_dict = dict_copy(volinfo->dict, NULL); + if (!set_dict) + return -1; + + ret = dict_get_str_sizen(set_dict, "xlator", &xlator); + if (!ret) { + ret = dict_get_str_sizen(set_dict, "loglevel", &loglevel); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED, + "could not get both" + " translator name and loglevel for log level " + "request"); + return -1; + } + } + + xl = volgen_graph_add(graph, "features/snapview-server", volinfo->volname); + if (!xl) + return -1; + + ret = xlator_set_fixed_option(xl, "volname", volinfo->volname); + if (ret) + return -1; + + xl = volgen_graph_add(graph, "performance/io-threads", volinfo->volname); + if (!xl) + return -1; + + snprintf(key, sizeof(key), "snapd-%s", volinfo->volname); + xl = volgen_graph_add_as(graph, "debug/io-stats", key); + if (!xl) + return -1; + + xl = volgen_graph_add(graph, "protocol/server", volinfo->volname); + if (!xl) + return -1; + + ret = xlator_set_fixed_option(xl, "transport-type", "tcp"); + if (ret) + return -1; + + if (dict_get_str_sizen(set_dict, "server.ssl", &ssl_str) == 0) { + if (gf_string2boolean(ssl_str, &ssl_bool) == 0) { + if (ssl_bool) { + ret = xlator_set_fixed_option( + xl, "transport.socket.ssl-enabled", "true"); + if (ret) { + return -1; + } + } + } + } + + RPC_SET_OPT(xl, SSL_OWN_CERT_OPT, "ssl-own-cert", return -1); + RPC_SET_OPT(xl, SSL_PRIVATE_KEY_OPT, "ssl-private-key", return -1); + RPC_SET_OPT(xl, SSL_CA_LIST_OPT, "ssl-ca-list", return -1); + RPC_SET_OPT(xl, SSL_CRL_PATH_OPT, "ssl-crl-path", return -1); + RPC_SET_OPT(xl, SSL_CERT_DEPTH_OPT, "ssl-cert-depth", return -1); + RPC_SET_OPT(xl, SSL_CIPHER_LIST_OPT, "ssl-cipher-list", return -1); + RPC_SET_OPT(xl, SSL_DH_PARAM_OPT, "ssl-dh-param", return -1); + RPC_SET_OPT(xl, SSL_EC_CURVE_OPT, "ssl-ec-curve", return -1); + + username = glusterd_auth_get_username(volinfo); + passwd = glusterd_auth_get_password(volinfo); + + ret = snprintf(key, sizeof(key), "auth.login.snapd-%s.allow", + volinfo->volname); + ret = xlator_set_option(xl, key, ret, username); + if (ret) + return -1; + + ret = snprintf(key, sizeof(key), "auth.login.%s.password", username); + ret = xlator_set_option(xl, key, ret, passwd); + if (ret) + return -1; + + snprintf(key, sizeof(key), "snapd-%s", volinfo->volname); + ret = xlator_set_fixed_option(xl, "auth-path", key); + if (ret) + return -1; + + ret = volgen_graph_set_options_generic( + graph, set_dict, (xlator && loglevel) ? (void *)set_dict : volinfo, + (xlator && loglevel) ? &server_spec_extended_option_handler + : &server_spec_option_handler); + + return ret; +} - filepath = GF_CALLOC (1, PATH_MAX, gf_common_mt_char); - if (!filepath) { - gf_log ("", GF_LOG_ERROR, "Unable to allocate nfs file path"); - goto out; - } +static int +prepare_bitrot_scrub_volume_options(glusterd_volinfo_t *volinfo, + dict_t *mod_dict, dict_t *set_dict) +{ + int ret = 0; + xlator_t *this = THIS; + GF_ASSERT(this); - VOLGEN_GET_NFS_DIR (path); + ret = dict_set_uint32(set_dict, "trusted-client", GF_CLIENT_TRUSTED); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=trusted-client", NULL); + goto out; + } - snprintf (filepath, PATH_MAX, "%s/nfs-server.vol", path); + dict_copy(volinfo->dict, set_dict); + if (mod_dict) + dict_copy(mod_dict, set_dict); - ret = filepath; out: - return ret; + return ret; } +static int +build_bitd_clusters(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, int brick_count, unsigned int numbricks) +{ + int ret = -1; + int clusters = 0; + xlator_t *xl = NULL; + char *brick_hint = NULL; + char *bitrot_args[] = {"features/bit-rot", "%s-bit-rot-%d"}; + + ret = volgen_link_bricks_from_list_tail(graph, volinfo, bitrot_args[0], + bitrot_args[1], brick_count, + brick_count); + clusters = ret; -static char * -get_client_filepath (glusterd_volinfo_t *volinfo) + xl = first_of(graph); + + ret = gf_asprintf(&brick_hint, "%d", numbricks); + if (ret < 0) + goto out; + + ret = xlator_set_fixed_option(xl, "brick-count", brick_hint); + if (ret) + goto out; + + ret = clusters; + +out: + GF_FREE(brick_hint); + brick_hint = NULL; + return ret; +} + +static int +build_bitd_volume_graph(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict, unsigned int numbricks) { - char path[PATH_MAX] = {0,}; - char *ret = NULL; - char *filename = NULL; + volgen_graph_t cgraph = {0}; + xlator_t *this = NULL; + xlator_t *xl = NULL; + dict_t *set_dict = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + int clusters = -1; + glusterd_brickinfo_t *brickinfo = NULL; + int brick_count = 0; + char transt[16] = { + 0, + }; + + this = THIS; + GF_ASSERT(this); + + priv = this->private; + GF_ASSERT(priv); + + set_dict = dict_new(); + if (!set_dict) { + gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + ret = -1; + goto out; + } + + ret = prepare_bitrot_scrub_volume_options(volinfo, mod_dict, set_dict); + if (ret) + goto out; + + get_transport_type(volinfo, set_dict, transt, _gf_false); + if (!strncmp(transt, "tcp,rdma", SLEN("tcp,rdma"))) + (void)snprintf(transt, sizeof(transt), "%s", "tcp"); + + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + if (!glusterd_is_local_brick(this, volinfo, brickinfo)) + continue; + + xl = volgen_graph_build_client(&cgraph, volinfo, brickinfo->hostname, + NULL, brickinfo->path, + brickinfo->brick_id, transt, set_dict); + if (!xl) { + ret = -1; + goto out; + } + brick_count++; + } + + if (brick_count == 0) { + ret = 0; + goto out; + } - filename = GF_CALLOC (1, PATH_MAX, gf_gld_mt_char); - if (!filename) - goto out; + clusters = build_bitd_clusters(&cgraph, volinfo, set_dict, brick_count, + numbricks); + if (clusters < 0) { + ret = -1; + goto out; + } - VOLGEN_GET_VOLUME_DIR (path, volinfo); + ret = volgen_graph_set_options_generic(&cgraph, set_dict, volinfo, + bitrot_option_handler); + if (ret) + goto out; - snprintf (filename, PATH_MAX, "%s/%s-fuse.vol", - path, volinfo->volname); + ret = volgen_graph_merge_sub(graph, &cgraph, clusters); + if (ret) + goto out; + + ret = graph_set_generic_options(this, graph, set_dict, "Bitrot"); - ret = filename; out: - return ret; + if (set_dict) + dict_unref(set_dict); + + return ret; +} + +int +build_bitd_graph(volgen_graph_t *graph, dict_t *mod_dict) +{ + glusterd_volinfo_t *voliter = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + xlator_t *iostxl = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + unsigned int numbricks = 0; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + iostxl = volgen_graph_add_as(graph, "debug/io-stats", "bitd"); + if (!iostxl) { + ret = -1; + goto out; + } + + /* TODO: do way with this extra loop _if possible_ */ + cds_list_for_each_entry(voliter, &priv->volumes, vol_list) + { + if (voliter->status != GLUSTERD_STATUS_STARTED) + continue; + if (!glusterd_is_bitrot_enabled(voliter)) + continue; + + cds_list_for_each_entry(brickinfo, &voliter->bricks, brick_list) + { + if (!glusterd_is_local_brick(this, voliter, brickinfo)) + continue; + numbricks++; + } + } + + cds_list_for_each_entry(voliter, &priv->volumes, vol_list) + { + if (voliter->status != GLUSTERD_STATUS_STARTED) + continue; + + if (!glusterd_is_bitrot_enabled(voliter)) + continue; + + ret = build_bitd_volume_graph(graph, voliter, mod_dict, numbricks); + } +out: + return ret; } static int -generate_brick_volfiles (glusterd_volinfo_t *volinfo) +build_scrub_clusters(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, int brick_count) { - glusterd_brickinfo_t *brickinfo = NULL; - int ret = -1; + int ret = -1; + int clusters = 0; + xlator_t *xl = NULL; + char *scrub_args[] = {"features/bit-rot", "%s-bit-rot-%d"}; - list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - gf_log ("", GF_LOG_DEBUG, - "Found a brick - %s:%s", brickinfo->hostname, - brickinfo->path); + ret = volgen_link_bricks_from_list_tail( + graph, volinfo, scrub_args[0], scrub_args[1], brick_count, brick_count); + clusters = ret; - ret = glusterd_generate_brick_volfile (volinfo, brickinfo); - if (ret) - goto out; + xl = first_of(graph); - } + ret = xlator_set_fixed_option(xl, "scrubber", "true"); + if (ret) + goto out; - ret = 0; + ret = clusters; out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + return ret; } static int -glusterfsd_write_nfs_xlator (int fd, char *subvols, char *volume_ids) +build_scrub_volume_graph(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict) { - char *dup_subvols = NULL; - char *subvols_remain = NULL; - char *subvol = NULL; - char *str = NULL; - char *free_ptr = NULL; - const char *nfs_str = "volume nfs-server\n" - "type nfs/server\n"; + volgen_graph_t cgraph = {0}; + dict_t *set_dict = NULL; + xlator_t *this = NULL; + xlator_t *xl = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + int clusters = -1; + int brick_count = 0; + char transt[16] = { + 0, + }; + glusterd_brickinfo_t *brickinfo = NULL; + + this = THIS; + GF_ASSERT(this); + + priv = this->private; + GF_ASSERT(priv); + + set_dict = dict_new(); + if (!set_dict) { + ret = -1; + goto out; + } + + ret = prepare_bitrot_scrub_volume_options(volinfo, mod_dict, set_dict); + if (ret) + goto out; + + get_transport_type(volinfo, set_dict, transt, _gf_false); + if (!strncmp(transt, "tcp,rdma", SLEN("tcp,rdma"))) + (void)snprintf(transt, sizeof(transt), "%s", "tcp"); + + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + if (!glusterd_is_local_brick(this, volinfo, brickinfo)) + continue; + + xl = volgen_graph_build_client(&cgraph, volinfo, brickinfo->hostname, + NULL, brickinfo->path, + brickinfo->brick_id, transt, set_dict); + if (!xl) { + ret = -1; + goto out; + } + brick_count++; + } + + if (brick_count == 0) { + ret = 0; + goto out; + } - if (fd <= 0) - return -1; + clusters = build_scrub_clusters(&cgraph, volinfo, set_dict, brick_count); + if (clusters < 0) { + ret = -1; + goto out; + } - dup_subvols = gf_strdup (subvols); - if (!dup_subvols) - return -1; - else - free_ptr = dup_subvols; + ret = volgen_graph_set_options_generic(&cgraph, set_dict, volinfo, + scrubber_option_handler); + if (ret) + goto out; - write (fd, nfs_str, strlen(nfs_str)); + ret = volgen_graph_merge_sub(graph, &cgraph, clusters); + if (ret) + goto out; - subvol = strtok_r (dup_subvols, " \n", &subvols_remain); - while (subvol) { - str = "option rpc-auth.addr."; - write (fd, str, strlen (str)); - write (fd, subvol, strlen (subvol)); - str = ".allow *\n"; - write (fd, str, strlen (str)); - subvol = strtok_r (NULL, " \n", &subvols_remain); - } - str = "option nfs.dynamic-volumes on\n"; - write (fd, str, strlen (str)); + ret = graph_set_generic_options(this, graph, set_dict, "Scrubber"); +out: + if (set_dict) + dict_unref(set_dict); + + return ret; +} + +int +build_scrub_graph(volgen_graph_t *graph, dict_t *mod_dict) +{ + glusterd_volinfo_t *voliter = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + xlator_t *iostxl = NULL; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + iostxl = volgen_graph_add_as(graph, "debug/io-stats", "scrub"); + if (!iostxl) { + ret = -1; + goto out; + } + + cds_list_for_each_entry(voliter, &priv->volumes, vol_list) + { + if (voliter->status != GLUSTERD_STATUS_STARTED) + continue; + + if (!glusterd_is_bitrot_enabled(voliter)) + continue; + + ret = build_scrub_volume_graph(graph, voliter, mod_dict); + } +out: + return ret; +} - /* Write fsids */ - write (fd, volume_ids, strlen (volume_ids)); +int +glusterd_snapdsvc_create_volfile(glusterd_volinfo_t *volinfo) +{ + volgen_graph_t graph = { + 0, + }; + int ret = -1; + char filename[PATH_MAX] = { + 0, + }; - str = "subvolumes "; - write (fd, str, strlen (str)); - write (fd, subvols, strlen (subvols)); - str = "\nend-volume\n"; - write (fd, str, strlen (str)); - GF_FREE (free_ptr); + graph.type = GF_SNAPD; + glusterd_svc_build_snapd_volfile(volinfo, filename, PATH_MAX); - return 0; + ret = glusterd_snapdsvc_generate_volfile(&graph, volinfo); + if (!ret) + ret = volgen_write_volfile(&graph, filename); + + volgen_graph_free(&graph); + + return ret; } int -volgen_generate_nfs_volfile (glusterd_volinfo_t *volinfo) -{ - char *nfs_filepath = NULL; - char *fuse_filepath = NULL; - int nfs_fd = -1; - int fuse_fd = -1; - int ret = -1; - char nfs_orig_path[PATH_MAX] = {0,}; - char *pad = NULL; - char *nfs_subvols = NULL; - char fuse_subvols[2048] = {0,}; - int subvol_len = 0; - char *nfs_vol_id = NULL; - char nfs_vol_id_opt[512] = {0,}; - char volume_id[64] = {0,}; - int nfs_volid_len = 0; - glusterd_volinfo_t *voliter = NULL; - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - if (!volinfo) { - gf_log ("", GF_LOG_ERROR, "Invalid Volume info"); - goto out; - } +glusterd_create_rb_volfiles(glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; - nfs_filepath = glusterd_get_nfs_filepath (volinfo); - if (!nfs_filepath) - goto out; + ret = glusterd_generate_brick_volfile(volinfo, brickinfo, NULL, NULL); + if (!ret) + ret = generate_client_volfiles(volinfo, GF_CLIENT_TRUSTED); + if (!ret) + ret = glusterd_fetchspec_notify(THIS); - strncat (nfs_filepath, ".tmp", PATH_MAX); - nfs_fd = open (nfs_filepath, O_WRONLY|O_TRUNC|O_CREAT, 0666); - if (nfs_fd < 0) { - gf_log ("", GF_LOG_ERROR, "Could not open file: %s", - nfs_filepath); - goto out; - } + return ret; +} +int +glusterd_create_volfiles(glusterd_volinfo_t *volinfo) +{ + int ret = -1; + xlator_t *this = NULL; + + this = THIS; + + ret = generate_brick_volfiles(volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL, + "Could not generate volfiles for bricks"); + goto out; + } + + ret = generate_client_volfiles(volinfo, GF_CLIENT_TRUSTED); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL, + "Could not generate trusted client volfiles"); + goto out; + } + + ret = generate_client_volfiles(volinfo, GF_CLIENT_TRUSTED_PROXY); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, + "Could not generate gfproxy client volfiles"); + goto out; + } + + ret = generate_client_volfiles(volinfo, GF_CLIENT_OTHER); + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL, + "Could not generate client volfiles"); + + ret = glusterd_generate_gfproxyd_volfile(volinfo); + if (ret) + gf_log(this->name, GF_LOG_ERROR, "Could not generate gfproxy volfiles"); + + ret = glusterd_shdsvc_create_volfile(volinfo); + if (ret) + gf_log(this->name, GF_LOG_ERROR, "Could not generate shd volfiles"); + + dict_del_sizen(volinfo->dict, "skip-CLIOT"); - list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (voliter->status != GLUSTERD_STATUS_STARTED) - continue; - else { - subvol_len += (strlen (voliter->volname) + 1); // ' ' - // "option nfs3.<volume>.volume-id <uuid>\n" - nfs_volid_len += (7 + 4 + 11 + 40 + - strlen (voliter->volname)); - } - } +out: + return ret; +} - if (subvol_len == 0) { - gf_log ("", GF_LOG_ERROR, "No volumes started"); - ret = -1; - goto out; - } - subvol_len++; //null character - nfs_subvols = GF_CALLOC (subvol_len, sizeof(*nfs_subvols), - gf_common_mt_char); - if (!nfs_subvols) { - gf_log ("", GF_LOG_ERROR, "Memory not available"); - ret = -1; - goto out; - } +int +glusterd_create_volfiles_and_notify_services(glusterd_volinfo_t *volinfo) +{ + int ret = -1; + xlator_t *this = NULL; - nfs_vol_id = GF_CALLOC (nfs_volid_len, sizeof (char), - gf_common_mt_char); - if (!nfs_vol_id) { - gf_log ("", GF_LOG_ERROR, "Memory not available"); - ret = -1; - goto out; - } + this = THIS; - voliter = NULL; - list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (voliter->status != GLUSTERD_STATUS_STARTED) - continue; + ret = glusterd_create_volfiles(volinfo); + if (ret) + goto out; - gf_log ("", GF_LOG_DEBUG, - "adding fuse info of - %s", voliter->volname); + ret = glusterd_fetchspec_notify(this); - snprintf (fuse_subvols, sizeof(fuse_subvols), " %s", voliter->volname); - fuse_filepath = get_client_filepath (voliter); - if (!fuse_filepath) { - ret = -1; - goto out; - } +out: + return ret; +} - fuse_fd = open (fuse_filepath, O_RDONLY); - if (fuse_fd < 0) { - gf_log ("", GF_LOG_ERROR, "Could not open file: %s", - fuse_filepath); - ret = -1; - goto out; - } +int +glusterd_create_global_volfile(glusterd_graph_builder_t builder, char *filepath, + dict_t *mod_dict) +{ + volgen_graph_t graph = { + 0, + }; + int ret = -1; - ret = glusterd_file_copy (nfs_fd, fuse_fd); - if (ret) - goto out; - GF_FREE (fuse_filepath); - fuse_filepath = NULL; - close (fuse_fd); - fuse_fd = -1; - if (subvol_len > strlen (fuse_subvols)) { - strncat (nfs_subvols, fuse_subvols, subvol_len - 1); - subvol_len -= strlen (fuse_subvols); - } else { - ret = -1; - gf_log ("", GF_LOG_ERROR, "Too many subvolumes"); - goto out; - } - uuid_unparse (voliter->volume_id, volume_id); - snprintf (nfs_vol_id_opt, 512, "option nfs3.%s.volume-id %s\n", - voliter->volname, volume_id); - strcat (nfs_vol_id, nfs_vol_id_opt); - } + ret = builder(&graph, mod_dict); + if (!ret) + ret = volgen_write_volfile(&graph, filepath); - ret = glusterfsd_write_nfs_xlator (nfs_fd, nfs_subvols, nfs_vol_id); - if (ret) - goto out; + volgen_graph_free(&graph); - strncpy (nfs_orig_path, nfs_filepath, PATH_MAX); - pad = strrchr (nfs_orig_path, '.'); - if (!pad) { - gf_log ("", GF_LOG_ERROR, "Failed to find the pad in nfs pat"); - ret = -1; - goto out; - } - *pad = '\0'; - ret = rename (nfs_filepath, nfs_orig_path); -out: - if (ret && nfs_filepath) - unlink (nfs_filepath); - if (fuse_filepath) - GF_FREE (fuse_filepath); - if (nfs_filepath) - GF_FREE (nfs_filepath); - if (nfs_vol_id) - GF_FREE (nfs_vol_id); - if (nfs_subvols) - GF_FREE (nfs_subvols); - if (fuse_fd > 0) - close (fuse_fd); - if (nfs_fd > 0) - close (nfs_fd); - return ret; + return ret; } -static int -generate_client_volfiles (glusterd_volinfo_t *volinfo) +int +glusterd_delete_volfile(glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo) { - char *filename = NULL; - int ret = -1; + int ret = 0; + char filename[PATH_MAX] = { + 0, + }; + + GF_ASSERT(volinfo); + GF_ASSERT(brickinfo); + + get_brick_filepath(filename, volinfo, brickinfo, NULL); + ret = sys_unlink(filename); + if (ret) + gf_msg("glusterd", GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "failed to delete file: %s", filename); + return ret; +} - filename = get_client_filepath (volinfo); - if (!filename) { - gf_log ("", GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; - } +int +validate_shdopts(glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) +{ + volgen_graph_t graph = { + 0, + }; + int ret = -1; - ret = generate_client_volfile (volinfo, filename); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate volfile for client"); - goto out; - } + graph.errstr = op_errstr; + if (!glusterd_is_shd_compatible_volume(volinfo)) { + ret = 0; + goto out; + } + ret = dict_set_int32_sizen(val_dict, "graph-check", 1); + if (ret) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Key=graph-check", NULL); + goto out; + } + ret = build_shd_graph(volinfo, &graph, val_dict); + if (!ret) + ret = graph_reconf_validateopt(&graph.graph, op_errstr); + + volgen_graph_free(&graph); + + gf_msg_debug("glusterd", 0, "Returning %d", ret); out: - if (filename) - GF_FREE (filename); - - return ret; + dict_del_sizen(val_dict, "graph-check"); + return ret; } +#ifdef BUILD_GNFS static int -glusterd_volgen_set_transport (glusterd_volinfo_t *volinfo) +validate_nfsopts(glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) { - int ret = 0; + volgen_graph_t graph = { + 0, + }; + int ret = -1; + char transport_type[16] = { + 0, + }; + char *tt = NULL; + char err_str[128] = { + 0, + }; + xlator_t *this = THIS; + + GF_ASSERT(this); + + graph.errstr = op_errstr; + + get_vol_transport_type(volinfo, transport_type); + ret = dict_get_str_sizen(val_dict, "nfs.transport-type", &tt); + if (!ret) { + if (volinfo->transport_type != GF_TRANSPORT_BOTH_TCP_RDMA) { + snprintf(err_str, sizeof(err_str), + "Changing nfs " + "transport type is allowed only for volumes " + "of transport type tcp,rdma"); + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_OP_UNSUPPORTED, "%s", + err_str); + *op_errstr = gf_strdup(err_str); + ret = -1; + goto out; + } + if (strcmp(tt, "tcp") && strcmp(tt, "rdma")) { + snprintf(err_str, sizeof(err_str), + "wrong transport " + "type %s", + tt); + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_INCOMPATIBLE_VALUE, + "Type=%s", tt, NULL); + *op_errstr = gf_strdup(err_str); + ret = -1; + goto out; + } + } + + ret = dict_set_str_sizen(val_dict, "volume-name", volinfo->volname); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_SET_FAILED, + "Failed to set volume name"); + goto out; + } + + ret = build_nfs_graph(&graph, val_dict); + if (!ret) + ret = graph_reconf_validateopt(&graph.graph, op_errstr); + + volgen_graph_free(&graph); - GF_ASSERT (volinfo->dict); +out: + if (dict_get_sizen(val_dict, "volume-name")) + dict_del_sizen(val_dict, "volume-name"); + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; +} +#endif - if(volinfo->transport_type == GF_TRANSPORT_RDMA) { - ret = set_xlator_option (volinfo->dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - "rdma"); - ret = set_xlator_option (volinfo->dict, VOLGEN_SERVER_OPTION_TRANSTYPE, - "rdma"); - } else { - ret = set_xlator_option (volinfo->dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - "tcp"); - ret = set_xlator_option (volinfo->dict, VOLGEN_SERVER_OPTION_TRANSTYPE, - "tcp"); - } +int +validate_clientopts(glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) +{ + volgen_graph_t graph = { + 0, + }; + int ret = -1; - return 0; + GF_ASSERT(volinfo); + + graph.errstr = op_errstr; + + ret = build_client_graph(&graph, volinfo, val_dict); + if (!ret) + ret = graph_reconf_validateopt(&graph.graph, op_errstr); + + volgen_graph_free(&graph); + + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; } int -glusterd_rb_create_volfiles (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +validate_brickopts(glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo, + dict_t *mod_dict, void *reconf) { - int ret = -1; + volgen_graph_t graph = { + 0, + }; + int ret = -1; + struct gd_validate_reconf_opts *brickreconf = reconf; + dict_t *val_dict = brickreconf->options; + char **op_errstr = brickreconf->op_errstr; + dict_t *full_dict = NULL; - glusterd_volgen_set_transport (volinfo); + GF_ASSERT(volinfo); - ret = glusterd_generate_brick_volfile (volinfo, brickinfo); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate volfiles for bricks"); - goto out; - } + graph.errstr = op_errstr; + full_dict = dict_new(); + if (!full_dict) { + gf_smsg("glusterd", GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL, NULL); + ret = -1; + goto out; + } - ret = generate_client_volfiles (volinfo); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate volfile for client"); - goto out; - } + if (mod_dict) + dict_copy(mod_dict, full_dict); + + if (val_dict) + dict_copy(val_dict, full_dict); + + ret = build_server_graph(&graph, volinfo, full_dict, brickinfo); + if (!ret) + ret = graph_reconf_validateopt(&graph.graph, op_errstr); - ret = glusterd_fetchspec_notify (THIS); + volgen_graph_free(&graph); out: - return ret; + if (full_dict) + dict_unref(full_dict); + + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; } int -glusterd_create_volfiles (glusterd_volinfo_t *volinfo) +glusterd_validate_brickreconf(glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) { - int ret = -1; + int ret = -1; + struct gd_validate_reconf_opts brickreconf = {0}; + + brickreconf.options = val_dict; + brickreconf.op_errstr = op_errstr; + ret = glusterd_volume_brick_for_each(volinfo, &brickreconf, + validate_brickopts); + return ret; +} - glusterd_volgen_set_transport (volinfo); +static int +_check_globalopt(dict_t *this, char *key, data_t *value, void *ret_val) +{ + int *ret = NULL; - ret = generate_brick_volfiles (volinfo); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate volfiles for bricks"); - goto out; - } + ret = ret_val; + if (*ret) + return 0; + if (!glusterd_check_globaloption(key)) + *ret = 1; - ret = generate_client_volfiles (volinfo); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate volfile for client"); - goto out; - } + return 0; +} - ret = glusterd_fetchspec_notify (THIS); +int +glusterd_validate_globalopts(glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) +{ + int ret = 0; + + dict_foreach(val_dict, _check_globalopt, &ret); + if (ret) { + *op_errstr = gf_strdup("option specified is not a global option"); + return -1; + } + ret = glusterd_validate_brickreconf(volinfo, val_dict, op_errstr); + + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate bricks"); + goto out; + } + + ret = validate_clientopts(volinfo, val_dict, op_errstr); + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate client"); + goto out; + } +#ifdef BUILD_GNFS + ret = validate_nfsopts(volinfo, val_dict, op_errstr); + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate nfs"); + goto out; + } +#endif + ret = validate_shdopts(volinfo, val_dict, op_errstr); + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate self-heald"); + goto out; + } out: - return ret; + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; +} + +static int +_check_localopt(dict_t *this, char *key, data_t *value, void *ret_val) +{ + int *ret = NULL; + + ret = ret_val; + if (*ret) + return 0; + if (!glusterd_check_localoption(key)) + *ret = 1; + + return 0; } int -glusterd_delete_volfile (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +glusterd_validate_reconfopts(glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) { - char *filename = NULL; + int ret = 0; + + dict_foreach(val_dict, _check_localopt, &ret); + if (ret) { + *op_errstr = gf_strdup("option specified is not a local option"); + return -1; + } + ret = glusterd_validate_brickreconf(volinfo, val_dict, op_errstr); + + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate bricks"); + goto out; + } + + ret = validate_clientopts(volinfo, val_dict, op_errstr); + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate client"); + goto out; + } + +#ifdef BUILD_GNFS + ret = validate_nfsopts(volinfo, val_dict, op_errstr); + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate nfs"); + goto out; + } +#endif + ret = validate_shdopts(volinfo, val_dict, op_errstr); + if (ret) { + gf_msg_debug("glusterd", 0, "Could not Validate self-heald"); + goto out; + } - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); +out: + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; +} - filename = get_brick_filename (volinfo, brickinfo); +struct volopt_map_entry * +gd_get_vmep(const char *key) +{ + char *completion = NULL; + struct volopt_map_entry *vmep = NULL; + int ret = 0; - if (filename) - unlink (filename); + if (!key) + return NULL; - if (filename) - GF_FREE (filename); - return 0; + COMPLETE_OPTION((char *)key, completion, ret); + for (vmep = glusterd_volopt_map; vmep->key; vmep++) { + if (strcmp(vmep->key, key) == 0) + return vmep; + } + + return NULL; } -int -glusterd_generate_brick_volfile (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +uint32_t +glusterd_get_op_version_from_vmep(struct volopt_map_entry *vmep) { - char *filename = NULL; - int ret = -1; + if (vmep) + return vmep->op_version; - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); + return 0; +} - filename = get_brick_filename (volinfo, brickinfo); +gf_boolean_t +gd_is_client_option(struct volopt_map_entry *vmep) +{ + if (vmep && (vmep->flags & VOLOPT_FLAG_CLIENT_OPT)) + return _gf_true; - if (!filename) { - gf_log ("", GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; - } + return _gf_false; +} - ret = generate_server_volfile (brickinfo, volinfo->dict, - filename); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not generate volfile for brick %s:%s", - brickinfo->hostname, brickinfo->path); - goto out; - } +gf_boolean_t +gd_is_xlator_option(struct volopt_map_entry *vmep) +{ + if (vmep && (vmep->flags & VOLOPT_FLAG_XLATOR_OPT)) + return _gf_true; - ret = 0; + return _gf_false; +} + +static volume_option_type_t +_gd_get_option_type(struct volopt_map_entry *vmep) +{ + void *dl_handle = NULL; + volume_opt_list_t vol_opt_list = { + {0}, + }; + int ret = -1; + volume_option_t *opt = NULL; + char *xlopt_key = NULL; + volume_option_type_t opt_type = GF_OPTION_TYPE_MAX; + + if (vmep) { + CDS_INIT_LIST_HEAD(&vol_opt_list.list); + ret = xlator_volopt_dynload(vmep->voltype, &dl_handle, &vol_opt_list); + if (ret) + goto out; + + if (_get_xlator_opt_key_from_vme(vmep, &xlopt_key)) + goto out; + + opt = xlator_volume_option_get_list(&vol_opt_list, xlopt_key); + _free_xlator_opt_key(xlopt_key); + + if (opt) + opt_type = opt->type; + } out: - if (filename) - GF_FREE (filename); + if (dl_handle) { + dlclose(dl_handle); + dl_handle = NULL; + } - return ret; + return opt_type; +} + +gf_boolean_t +gd_is_boolean_option(struct volopt_map_entry *vmep) +{ + if (GF_OPTION_TYPE_BOOL == _gd_get_option_type(vmep)) + return _gf_true; + + return _gf_false; +} + +int +glusterd_shdsvc_generate_volfile(glusterd_volinfo_t *volinfo, char *filename, + dict_t *mode_dict) +{ + int ret = -1; + volgen_graph_t graph = { + 0, + }; + + graph.type = GF_SHD; + ret = build_shd_graph(volinfo, &graph, mode_dict); + if (!ret) + ret = volgen_write_volfile(&graph, filename); + + volgen_graph_free(&graph); + + return ret; } |
