diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-volgen.c')
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 4918 |
1 files changed, 3458 insertions, 1460 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index ec12e4542..6f3c69e7d 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -1,456 +1,677 @@ /* - 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> + +#if (HAVE_LIB_XML) +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> +#endif + #include "xlator.h" -#include "protocol-common.h" #include "glusterd.h" #include "defaults.h" -#include "list.h" +#include "logging.h" #include "dict.h" -#include "compat.h" -#include "compat-errno.h" -#include "glusterd-sm.h" -#include "glusterd-op-sm.h" -#include "cli1.h" +#include "graph-utils.h" +#include "glusterd-store.h" +#include "glusterd-hooks.h" +#include "trie.h" #include "glusterd-mem-types.h" +#include "cli1-xdr.h" #include "glusterd-volgen.h" +#include "glusterd-op-sm.h" #include "glusterd-utils.h" +#include "run.h" +#include "options.h" -int -set_xlator_option (dict_t *dict, char *key, - char *value) -{ - int ret = 0; - char *str = NULL; +extern struct volopt_map_entry glusterd_volopt_map[]; - str = GF_CALLOC (1, strlen (value) + 1, - gf_gld_mt_char); +/********************************************* + * + * xlator generation / graph manipulation API + * + *********************************************/ - if (!str) - return -1; - strncpy (str, value, strlen (value)); +struct volgen_graph { + char **errstr; + glusterfs_graph_t graph; +}; +typedef struct volgen_graph volgen_graph_t; - ret = dict_set_dynstr (dict, key, str); +static void +set_graph_errstr (volgen_graph_t *graph, const char *str) +{ + if (!graph->errstr) + return; - return ret; + *graph->errstr = gf_strdup (str); } -static int32_t -set_default_options (dict_t *dict, char *volname) +static xlator_t * +xlator_instantiate_va (const char *type, const char *format, va_list arg) { - int ret = -1; + xlator_t *xl = NULL; + char *volname = NULL; + int ret = 0; - ret = dict_set_str (dict, "volname", - volname); - if (ret) - goto out; + ret = gf_vasprintf (&volname, format, arg); + if (ret < 0) { + volname = NULL; - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_ODIRECT, - "on"); - if (ret) - goto out; + goto error; + } - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_STATFSSIZE, - "on"); + xl = GF_CALLOC (1, sizeof (*xl), gf_common_mt_xlator_t); + if (!xl) + goto error; + ret = xlator_set_type_virtual (xl, type); if (ret) - goto out; + goto error; + xl->options = get_new_dict(); + if (!xl->options) + goto error; + xl->name = volname; + INIT_LIST_HEAD (&xl->volume_options); - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_MANDATTR, - "on"); - if (ret) - goto out; + xl->ctx = THIS->ctx; - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_SPANDEVICES, - "1"); - if (ret) - goto out; + return xl; - ret = set_xlator_option (dict, VOLGEN_POSIX_OPTION_BCKUNLINK, - "on"); - if (ret) - goto out; + error: + gf_log ("", GF_LOG_ERROR, "creating xlator of type %s failed", + type); + GF_FREE (volname); + if (xl) + xlator_destroy (xl); - ret = set_xlator_option (dict, VOLGEN_LOCKS_OPTION_TRACE, - "on"); - if (ret) - goto out; + return NULL; +} - ret = set_xlator_option (dict, VOLGEN_LOCKS_OPTION_MAND, - "on"); - if (ret) - goto out; +#ifdef __not_used_as_of_now_ +static xlator_t * +xlator_instantiate (const char *type, const char *format, ...) +{ + va_list arg; + xlator_t *xl; - ret = set_xlator_option (dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - "tcp"); - 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_NODELAY, - "on"); - if (ret) - goto out; + return xl; +} +#endif - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_THREADCOUNT, - "16"); - if (ret) - goto out; +static int +volgen_xlator_link (xlator_t *pxl, xlator_t *cxl) +{ + int ret = 0; - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_AUTOSCALING, - "on"); - if (ret) - goto out; + ret = glusterfs_xlator_link (pxl, cxl); + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, + "Out of memory, cannot link xlators %s <- %s", + pxl->name, cxl->name); + } - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_MINTHREADS, - "on"); - if (ret) - goto out; + return ret; +} - ret = set_xlator_option (dict, VOLGEN_IOT_OPTION_MAXTHREADS, - "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_SERVER_OPTION_TRANSTYPE, - "tcp"); - 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_log ("", GF_LOG_ERROR, "failed to add graph entry %s", + xl->name); - ret = set_xlator_option (dict, VOLGEN_SERVER_OPTION_NODELAY, - "on"); - if (ret) - goto out; + return -1; + } - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_READSUBVOL, - "on"); - if (ret) - goto out; + return 0; +} - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_FAVCHILD, - "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_REPLICATE_OPTION_BCKSHCOUNT, - "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_REPLICATE_OPTION_DATASH, - "on"); - if (ret) - goto out; + if (!xl) + return NULL; - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_DATASHALGO, - "on"); - if (ret) - goto out; + if (volgen_graph_link (graph, xl)) { + xlator_destroy (xl); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_SHWINDOWSIZE, - "on"); - if (ret) - goto out; + return NULL; + } else + glusterfs_graph_set_first (&graph->graph, xl); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_METASH, - "on"); - if (ret) - goto out; + return xl; +} - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_ENTRYSH, - "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_REPLICATE_OPTION_DATACHANGELOG, - "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_REPLICATE_OPTION_METADATACHANGELOG, - "on"); - if (ret) - goto out; + if (!xl) + return NULL; - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_ENTRYCHANGELOG, - "on"); - if (ret) - goto out; + glusterfs_graph_set_first (&graph->graph, xl); - ret = set_xlator_option (dict, VOLGEN_REPLICATE_OPTION_STRICTREADDIR, - "on"); - if (ret) - goto out; + return xl; +} - ret = set_xlator_option (dict, VOLGEN_STRIPE_OPTION_BLOCKSIZE, - "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_STRIPE_OPTION_USEXATTR, - "on"); - if (ret) - goto out; + shorttype = strrchr (type, '/'); + GF_ASSERT (shorttype); + shorttype++; + GF_ASSERT (*shorttype); - ret = set_xlator_option (dict, VOLGEN_DHT_OPTION_LOOKUPUNHASH, - "on"); - if (ret) - goto out; + return volgen_graph_add_as (graph, type, "%s-%s", volname, shorttype); +} - ret = set_xlator_option (dict, VOLGEN_DHT_OPTION_MINFREEDISK, - "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, char *value) +{ + char *dval = NULL; - ret = set_xlator_option (dict, VOLGEN_DHT_OPTION_UNHASHSTICKY, - "on"); - if (ret) - goto out; + dval = gf_strdup (value); + if (!dval) { + gf_log ("", GF_LOG_ERROR, + "failed to set xlator opt: %s[%s] = %s", + xl->name, key, value); - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_FLUSHBEHIND, - "on"); - if (ret) - goto out; + return -1; + } - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_CACHESIZE, - "on"); - if (ret) - goto out; + return dict_set_dynstr (xl->options, key, dval); +} - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_DISABLENBYTES, - "on"); - if (ret) - goto out; +static int +xlator_get_option (xlator_t *xl, char *key, char **value) +{ + GF_ASSERT (xl); + return dict_get_str (xl->options, key, value); +} - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_OSYNC, - "on"); - if (ret) - goto out; +static inline xlator_t * +first_of (volgen_graph_t *graph) +{ + return (xlator_t *)graph->graph.first; +} - ret = set_xlator_option (dict, VOLGEN_WB_OPTION_TRICKLINGWRITES, - "on"); - if (ret) - goto out; - ret = set_xlator_option (dict, VOLGEN_RA_OPTION_ATIME, - "on"); - if (ret) - goto out; - ret = set_xlator_option (dict, VOLGEN_RA_OPTION_PAGECOUNT, - "on"); - if (ret) - goto out; - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_PRIORITY, - "on"); - if (ret) - goto out; +/************************** + * + * Trie glue + * + *************************/ - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_TIMEOUT, - "on"); - if (ret) - goto out; - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_CACHESIZE, - "on"); - if (ret) - goto out; +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++; + } - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_MINFILESIZE, - "on"); - if (ret) - goto out; + 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) + return -1; + next: + continue; + } - ret = set_xlator_option (dict, VOLGEN_IOCACHE_OPTION_MAXFILESIZE, - "on"); - if (ret) - goto out; + return 0; +} - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_PRIORITY, - "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_QR_OPTION_TIMEOUT, - "on"); - if (ret) - goto out; +static int +process_nodevec (struct trienodevec *nodevec, char **hint) +{ + int ret = 0; + char *hint1 = NULL; + char *hint2 = NULL; + char *hintinfx = ""; + trienode_t **nodes = nodevec->nodes; - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_CACHESIZE, - "on"); - if (ret) - goto out; + if (!nodes[0]) { + *hint = NULL; + return 0; + } - ret = set_xlator_option (dict, VOLGEN_QR_OPTION_MAXFILESIZE, - "on"); - if (ret) - goto out; +#if 0 + /* Limit as in git */ + if (trienode_get_dist (nodes[0]) >= 6) { + *hint = NULL; + return 0; + } +#endif - ret = 0; + if (trienode_get_word (nodes[0], &hint1)) + return -1; -out: + if (nodevec->cnt < 2 || !nodes[1]) { + *hint = hint1; + return 0; + } + + if (trienode_get_word (nodes[1], &hint2)) + return -1; + + if (*hint) + hintinfx = *hint; + ret = gf_asprintf (hint, "%s or %s%s", hint1, hintinfx, hint2); + if (ret > 0) + ret = 0; return ret; } -int32_t -glusterd_default_xlator_options (glusterd_volinfo_t *volinfo) +static int +volopt_trie_section (int lvl, char **patt, char *word, char **hint, int hints) { - int ret = -1; + trienode_t *nodes[] = { NULL, NULL }; + struct trienodevec nodevec = { nodes, 2}; + trie_t *trie = NULL; + int ret = 0; - volinfo->dict = dict_new (); - if (!volinfo->dict) { - ret = -1; - goto out; - } + trie = trie_new (); + if (!trie) + return -1; - ret = set_default_options (volinfo->dict, - volinfo->volname); - if (ret) { - dict_unref (volinfo->dict); - goto out; + if (volopt_selector (lvl, patt, trie, &volopt_trie_cbk)) { + trie_destroy (trie); + + return -1; } - ret = 0; + GF_ASSERT (hints <= 2); + nodevec.cnt = hints; + ret = trie_measure_vec (trie, word, &nodevec); + if (ret || !nodevec.nodes[0]) + trie_destroy (trie); -out: - return ret; + ret = process_nodevec (&nodevec, hint); + trie_destroy (trie); + return ret; } static int -__write_posix_xlator (FILE *file, dict_t *dict, - char *posix_directory) -{ - 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; - - 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"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +volopt_trie (char *key, char **hint) +{ + char *patt[] = { NULL }; + char *fullhint = 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, 2); + + len = dot - key; + dom = gf_strdup (key); + if (!dom) + return -1; + dom[len] = '\0'; - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_ODIRECT, - &opt_odirect); + ret = volopt_trie_section (0, NULL, dom, patt, 1); + GF_FREE (dom); if (ret) { + patt[0] = NULL; goto out; } - - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_STATFSSIZE, - &opt_statfssize); - if (ret) { + if (!patt[0]) goto out; - } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_MANDATTR, - &opt_mandattr); - if (ret) { + *hint = "..."; + ret = volopt_trie_section (1, patt, dot + 1, hint, 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 = dict_get_str (dict, VOLGEN_POSIX_OPTION_SPANDEVICES, - &opt_spandevices); - if (ret) { - goto out; + out: + GF_FREE (patt[0]); + if (ret) + *hint = NULL; + + return ret; +} + + + + +/************************** + * + * 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 int +process_option (char *key, data_t *value, void *param) +{ + struct opthandler_data *odt = param; + struct volopt_map_entry vme = {0,}; + + if (odt->rv) + return 0; + 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 0; +} + +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; + + odt.graph = graph; + odt.handler = handler; + odt.param = param; + (void)data; + + for (vme = glusterd_volopt_map; vme->key; vme++) { + odt.vme = vme; + odt.found = _gf_false; + odt.data_t_fake = _gf_false; + + data = dict_get (dict, vme->key); + + 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; + } } - ret = dict_get_str (dict, VOLGEN_POSIX_OPTION_BCKUNLINK, - &opt_bckunlink); - if (ret) { - goto out; + return 0; +} + +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; + + ret = xlator_set_option (trav, vme->option, vme->value); + if (ret) + break; } + return ret; +} - fprintf (file, posix_str, - volname, - "posix", - posix_directory, - opt_odirect, - opt_statfssize, - opt_mandattr, - opt_spandevices, - opt_bckunlink); +static int +basic_option_handler (volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + int ret = 0; - ret = 0; + if (vme->option[0] == '!') + goto out; + ret = no_filter_option_handler (graph, vme, param); out: return ret; } static int -__write_locks_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - char *volname = NULL; - char *opt_trace = NULL; - char *opt_mand = NULL; - int ret = -1; - - 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"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +volgen_graph_set_options (volgen_graph_t *graph, dict_t *dict) +{ + return volgen_graph_set_options_generic (graph, dict, NULL, + &basic_option_handler); +} - ret = dict_get_str (dict, VOLGEN_LOCKS_OPTION_TRACE, - &opt_trace); - if (ret) { - goto out; +static int +optget_option_handler (volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + struct volopt_map_entry *vme2 = param; + + if (strcmp (vme->key, vme2->key) == 0) + vme2->value = vme->value; + + return 0; +} + +static glusterd_server_xlator_t +get_server_xlator (char *xlator) +{ + glusterd_server_xlator_t subvol = GF_XLATOR_NONE; + + if (strcmp (xlator, "posix") == 0) + subvol = GF_XLATOR_POSIX; + if (strcmp (xlator, "acl") == 0) + subvol = GF_XLATOR_ACL; + if (strcmp (xlator, "locks") == 0) + subvol = GF_XLATOR_LOCKS; + if (strcmp (xlator, "io-threads") == 0) + subvol = GF_XLATOR_IOT; + if (strcmp (xlator, "index") == 0) + subvol = GF_XLATOR_INDEX; + if (strcmp (xlator, "marker") == 0) + subvol = GF_XLATOR_MARKER; + if (strcmp (xlator, "io-stats") == 0) + subvol = GF_XLATOR_IO_STATS; + if (strcmp (xlator, "bd") == 0) + subvol = GF_XLATOR_BD; + + return subvol; +} + +static glusterd_client_xlator_t +get_client_xlator (char *xlator) +{ + glusterd_client_xlator_t subvol = GF_CLNT_XLATOR_NONE; + + if (strcmp (xlator, "client") == 0) + subvol = GF_CLNT_XLATOR_FUSE; + + return subvol; +} + +static int +debugxl_option_handler (volgen_graph_t *graph, struct volopt_map_entry *vme, + void *param) +{ + char *volname = NULL; + gf_boolean_t enabled = _gf_false; + + volname = param; + + if (strcmp (vme->option, "!debug") != 0) + return 0; + + if (!strcmp (vme->key , "debug.trace") || + !strcmp (vme->key, "debug.error-gen")) { + if (get_server_xlator (vme->value) == GF_XLATOR_NONE && + get_client_xlator (vme->value) == GF_CLNT_XLATOR_NONE) + return 0; + else + goto add_graph; } - ret = dict_get_str (dict, VOLGEN_LOCKS_OPTION_MAND, - &opt_mand); - if (ret) { - goto out; + if (gf_string2boolean (vme->value, &enabled) == -1) + return -1; + if (!enabled) + return 0; + +add_graph: + 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 ret = 0; + char *value_str = NULL; + + ret = dict_get_str (set_dict, "debug.trace", &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; + } } - fprintf (file, locks_str, - volname, - "locks", - opt_trace, - opt_mand, - subvolume); + ret = dict_get_str (set_dict, "debug.error-gen", &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; + } + } ret = 0; @@ -458,1610 +679,3387 @@ out: return ret; } +/* This getter considers defaults also. */ static int -__write_client_xlator (FILE *file, dict_t *dict, - char *remote_subvol, - char *remote_host, - int count) -{ - char *volname = NULL; - char *opt_transtype = NULL; - char *opt_nodelay = NULL; - int ret = 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" - " option remote-subvolume %s\n" - "end-volume\n\n"; - - ret = dict_get_str (dict, "volname", &volname); +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) { - goto out; + gf_log ("", GF_LOG_ERROR, "Out of memory"); + + return -1; } - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - &opt_transtype); - if (ret) { - goto out; + *value = vme.value; + + return 0; +} + +static int +option_complete (char *key, char **completion) +{ + struct volopt_map_entry *vme = NULL; + + *completion = NULL; + for (vme = glusterd_volopt_map; vme->key; vme++) { + if (strcmp (strchr (vme->key, '.') + 1, key) != 0) + continue; + + if (*completion && strcmp (*completion, vme->key) != 0) { + /* cancel on non-unique match */ + *completion = NULL; + + return 0; + } else + *completion = vme->key; } - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_NODELAY, - &opt_nodelay); + 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 boo = _gf_false; + int ret = 0; + + ret = glusterd_volinfo_get (volinfo, key, &val); + if (ret) + return -1; + + if (val) + ret = gf_string2boolean (val, &boo); if (ret) { - goto out; + gf_log ("", GF_LOG_ERROR, "value for %s option is not valid", key); + + return -1; } - fprintf (file, client_str, - volname, - "client", - count, - opt_transtype, - remote_host, - opt_nodelay, - remote_subvol); + return boo; +} - ret = 0; +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; + } + } -out: - return ret; + return _gf_false; } -static int -__write_replace_brick_xlator (FILE *file, dict_t *dict) +gf_boolean_t +glusterd_check_globaloption (char *key) { - char *volname = NULL; - char *opt_transtype = NULL; - char *opt_nodelay = NULL; - int ret = 0; + 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; + } + } + return _gf_false; +} - 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"; +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, "volname", &volname); - if (ret) { - goto out; + return _gf_false; +} + +int +glusterd_check_voloption (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 == DOC)) + return _gf_true; + else + return _gf_false; + } } - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_TRANSTYPE, - &opt_transtype); - 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_log (this->name, GF_LOG_ERROR, + "Out of memory"); + return -1; + } + + ret = !!*completion; + if (ret) + return ret; + else + goto trie; + } else + return 0; } - ret = dict_get_str (dict, VOLGEN_CLIENT_OPTION_NODELAY, - &opt_nodelay); + for (vmep = glusterd_volopt_map; vmep->key; vmep++) { + if (strcmp (vmep->key, key) == 0) { + ret = 1; + break; + } + } + + if (ret || !completion) + return ret; + + trie: + ret = volopt_trie (key, completion); if (ret) { - goto out; + gf_log (this->name, GF_LOG_ERROR, + "Some error occurred during keyword hinting"); } - fprintf (file, client_str, - volname, - "replace-brick", - opt_transtype, - opt_nodelay); + 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_log (THIS->name, GF_LOG_ERROR, "Unknown " + "transport type"); + } + + return trans_type; +} - ret = 0; +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; + 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); + if (ret) + goto out; + } + ret = 0; out: return ret; } static int -__write_pump_xlator (FILE *file, dict_t *dict, - char *subvolume) +volgen_graph_merge_sub (volgen_graph_t *dgraph, volgen_graph_t *sgraph, + size_t child_count) { - char *volname = NULL; - int ret = -1; + xlator_t *trav = NULL; + int ret = 0; - const char *pump_str = "volume %s-%s\n" - " type cluster/pump\n" - " subvolumes %s %s-replace-brick\n" - "end-volume\n\n"; + GF_ASSERT (dgraph->graph.first); - ret = dict_get_str (dict, "volname", &volname); - if (ret) { + ret = _xl_link_children (first_of (dgraph), first_of (sgraph), + child_count); + if (ret) goto out; - } - fprintf (file, pump_str, - volname, "pump", - subvolume, - volname); + for (trav = first_of (dgraph); trav->next; trav = trav->next); - ret = 0; + trav->next = first_of (sgraph); + trav->next->prev = trav; + dgraph->graph.xl_count += sgraph->graph.xl_count; out: return ret; } +static void +volgen_apply_filters (char *orig_volfile) +{ + DIR *filterdir = NULL; + struct dirent entry = {0,}; + struct dirent *next = NULL; + char *filterpath = NULL; + struct stat statbuf = {0,}; + + filterdir = opendir(FILTERDIR); + if (!filterdir) { + return; + } + + while ((readdir_r(filterdir,&entry,&next) == 0) && next) { + if (!strncmp(entry.d_name,".",sizeof(entry.d_name))) { + continue; + } + if (!strncmp(entry.d_name,"..",sizeof(entry.d_name))) { + continue; + } + /* + * d_type isn't guaranteed to be present/valid on all systems, + * so do an explicit stat instead. + */ + if (gf_asprintf(&filterpath,"%s/%.*s",FILTERDIR, + sizeof(entry.d_name), entry.d_name) == (-1)) { + continue; + } + /* Deliberately use stat instead of lstat to allow symlinks. */ + if (stat(filterpath,&statbuf) == (-1)) { + goto free_fp; + } + if (!S_ISREG(statbuf.st_mode)) { + goto free_fp; + } + /* + * 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 (access(filterpath,X_OK) != 0) { + goto free_fp; + } + if (runcmd(filterpath,orig_volfile,NULL)) { + gf_log("",GF_LOG_ERROR,"failed to run filter %.*s", + (int)sizeof(entry.d_name), entry.d_name); + } +free_fp: + GF_FREE(filterpath); + } +} + static int -__write_iothreads_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - char *volname = NULL; - char *opt_threadcount = NULL; - char *opt_autoscaling = NULL; - char *opt_minthreads = NULL; - char *opt_maxthreads = NULL; - int ret = -1; - - const char *iot_str = "volume %s\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"; - - ret = dict_get_str (dict, "export-path", &volname); - if (ret) { - goto out; - } +volgen_write_volfile (volgen_graph_t *graph, char *filename) +{ + char *ftmp = NULL; + FILE *f = NULL; + int fd = 0; + xlator_t *this = NULL; - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_THREADCOUNT, - &opt_threadcount); - if (ret) { - goto out; - } + this = THIS; - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_AUTOSCALING, - &opt_autoscaling); - if (ret) { - goto out; + if (gf_asprintf (&ftmp, "%s.tmp", filename) == -1) { + ftmp = NULL; + + goto error; } - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_MINTHREADS, - &opt_minthreads); - if (ret) { - goto out; + fd = creat (ftmp, S_IRUSR | S_IWUSR); + if (fd < 0) { + gf_log (this->name, GF_LOG_ERROR, "%s", + strerror (errno)); + goto error; } - ret = dict_get_str (dict, VOLGEN_IOT_OPTION_MAXTHREADS, - &opt_maxthreads); - if (ret) { - goto out; + close (fd); + + f = fopen (ftmp, "w"); + if (!f) + goto error; + + if (glusterfs_graph_print_file (f, &graph->graph) == -1) + goto error; + + if (fclose (f) != 0) { + gf_log (THIS->name, GF_LOG_ERROR, "fclose on the file %s " + "failed (%s)", ftmp, strerror (errno)); + /* + * 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; } - fprintf (file, iot_str, - volname, - opt_threadcount, - opt_autoscaling, - opt_minthreads, - opt_maxthreads, - subvolume); + f = NULL; - ret = 0; + if (rename (ftmp, filename) == -1) + goto error; -out: - return ret; + GF_FREE (ftmp); + + volgen_apply_filters(filename); + + return 0; + + error: + + GF_FREE (ftmp); + if (f) + fclose (f); + + gf_log (this->name, GF_LOG_ERROR, + "failed to create volfile %s", filename); + + return -1; } -static int -__write_access_control_xlator (FILE *file, dict_t *dict, - char *subvolume) +static void +volgen_graph_free (volgen_graph_t *graph) { - char *volname = NULL; - int ret = -1; + xlator_t *trav = NULL; + xlator_t *trav_old = NULL; - const char *ac_str = "volume %s-access-control\n" - "type features/access-control\n" - "subvolumes %s\n" - "end-volume\n"; + for (trav = first_of (graph) ;; trav = trav->next) { + if (trav_old) + xlator_destroy (trav_old); - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; + 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 (volinfo->dict, NULL); + if (!set_dict) + return -1; + dict_copy (mod_dict, set_dict); + /* XXX dict_copy swallows errors */ + } else { + set_dict = volinfo->dict; + } - fprintf (file, ac_str, volname, subvolume); - ret = 0; + ret = builder (graph, volinfo, set_dict, param); + if (!ret) + ret = volgen_graph_set_options (graph, set_dict); + + if (mod_dict) + dict_destroy (set_dict); -out: return ret; } -static int -__write_server_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - char *volname = NULL; - char *opt_transtype = NULL; - char *opt_nodelay = NULL; - int ret = -1; - - 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" - " subvolumes %s\n" - "end-volume\n\n"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; +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; } +} - ret = dict_get_str (dict, VOLGEN_SERVER_OPTION_TRANSTYPE, - &opt_transtype); - if (ret) { - goto out; +static void +get_vol_transport_type (glusterd_volinfo_t *volinfo, char *tt) +{ + transport_type_to_str (volinfo->transport_type, tt); +} + +static void +get_vol_nfs_transport_type (glusterd_volinfo_t *volinfo, char *tt) +{ + if (volinfo->nfs_transport_type == GF_TRANSPORT_BOTH_TCP_RDMA) { + gf_log ("", GF_LOG_ERROR, "%s:nfs transport cannot be both" + " tcp and rdma", volinfo->volname); + GF_ASSERT (0); } + transport_type_to_str (volinfo->nfs_transport_type, tt); +} - ret = dict_get_str (dict, VOLGEN_SERVER_OPTION_NODELAY, - &opt_nodelay); - if (ret) { - goto out; +/* 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; + char *key = NULL; + typedef void (*transport_type) (glusterd_volinfo_t *volinfo, char *tt); + transport_type get_transport; + + if (is_nfs == _gf_false) { + key = "client-transport-type"; + get_transport = get_vol_transport_type; + } else { + key = "nfs.transport-type"; + get_transport = get_vol_nfs_transport_type; + } + + ret = dict_get_str (set_dict, key, &tt); + if (ret) + get_transport (volinfo, transt); + 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; + xlator_list_t *trav = NULL; + char *aa = NULL; + int ret = 0; + char *key = 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; + + for (trav = xl->children; trav; trav = trav->next) { + ret = gf_asprintf (&aa, "auth.addr.%s.%s", trav->xlator->name, + key); + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + if (ret) + return -1; } - fprintf (file, server_str, - volname, "server", - opt_transtype, - subvolume, - opt_nodelay, - subvolume); + return 0; +} - ret = 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,}; -out: - return ret; + 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 -__write_replicate_xlator (FILE *file, dict_t *dict, - char *subvolume, - int replicate_count, - int subvol_count, - int count) -{ - 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; - - - const 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; - } +server_check_marker_off (volgen_graph_t *graph, struct volopt_map_entry *vme, + glusterd_volinfo_t *volinfo) +{ + gf_boolean_t bool = _gf_false; + int ret = 0; - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_READSUBVOL, - &opt_readsubvol); - if (ret) { - goto out; - } + GF_ASSERT (volinfo); + GF_ASSERT (vme); - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_FAVCHILD, - &opt_favchild); - if (ret) { + if (strcmp (vme->option, "!xtime") != 0) + return 0; + + ret = gf_string2boolean (vme->value, &bool); + if (ret || bool) goto out; - } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_BCKSHCOUNT, - &opt_bckshcount); - if (ret) { + ret = glusterd_volinfo_get_boolean (volinfo, VKEY_MARKER_XTIME); + if (ret < 0) { + gf_log ("", GF_LOG_WARNING, "failed to get the marker status"); + ret = -1; goto out; } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_DATASH, - &opt_datash); if (ret) { - goto out; + bool = _gf_false; + ret = glusterd_check_gsync_running (volinfo, &bool); + + if (bool) { + gf_log ("", GF_LOG_WARNING, 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; + } + + if (ret) { + gf_log ("", GF_LOG_WARNING, "Unable to get the status" + " of active gsync session"); + goto out; + } } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_DATASHALGO, - &opt_datashalgo); - if (ret) { + ret = 0; + out: + gf_log ("", GF_LOG_DEBUG, "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 +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; + + ret = dict_get_str (dict, "xlator", &xlator); + if (ret) goto out; - } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_SHWINDOWSIZE, - &opt_shwindowsize); - if (ret) { + ret = dict_get_str (dict, "loglevel", &loglevel); + if (ret) 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_log ("glusterd", GF_LOG_DEBUG, "Setting log level for xlator: %s", + trav->type); + ret = xlator_set_option (trav, "log-level", loglevel); + if (ret) + break; + } } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_METASH, - &opt_metash); - if (ret) { - goto out; + out: + return ret; +} + +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 = loglevel_option_handler (graph, vme, "brick"); + + if (!ret) + ret = sys_loglevel_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 +server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) +{ + char *volname = NULL; + char *path = NULL; + int pump = 0; + xlator_t *xl = NULL; + xlator_t *txl = NULL; + xlator_t *rbxl = NULL; + char transt[16] = {0,}; + char *ptranst = NULL; + char volume_id[64] = {0,}; + char tstamp_file[PATH_MAX] = {0,}; + int ret = 0; + char *xlator = NULL; + char *loglevel = NULL; + char *username = NULL; + char *password = NULL; + char index_basepath[PATH_MAX] = {0}; + char key[1024] = {0}; + glusterd_brickinfo_t *brickinfo = NULL; + char changelog_basepath[PATH_MAX] = {0,}; + + brickinfo = param; + path = brickinfo->path; + volname = volinfo->volname; + get_vol_transport_type (volinfo, transt); + + ret = dict_get_str (set_dict, "xlator", &xlator); + + /* got a cli log level request */ + if (!ret) { + ret = dict_get_str (set_dict, "loglevel", &loglevel); + if (ret) { + gf_log ("glusterd", GF_LOG_ERROR, "could not get both" + " translator name and loglevel for log level request"); + goto out; + } } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_ENTRYSH, - &opt_entrysh); - if (ret) { - goto out; + xl = volgen_graph_add (graph, "storage/posix", volname); + if (!xl) + return -1; + + ret = xlator_set_option (xl, "directory", path); + if (ret) + return -1; + + ret = xlator_set_option (xl, "volume-id", + uuid_utoa (volinfo->volume_id)); + if (ret) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, + "posix"); + if (ret) + return -1; +#ifdef HAVE_BD_XLATOR + if (*brickinfo->vg != '\0') { + /* Now add BD v2 xlator if volume is BD type */ + xl = volgen_graph_add (graph, "storage/bd", volname); + if (!xl) + return -1; + + ret = xlator_set_option (xl, "device", "vg"); + if (ret) + return -1; + ret = xlator_set_option (xl, "export", brickinfo->vg); + if (ret) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, "bd"); + if (ret) + return -1; + } +#endif - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_DATACHANGELOG, - &opt_datachangelog); - if (ret) { - goto out; + xl = volgen_graph_add (graph, "features/changelog", volname); + if (!xl) + return -1; + + ret = xlator_set_option (xl, "changelog-brick", path); + if (ret) + return -1; + + snprintf (changelog_basepath, sizeof (changelog_basepath), + "%s/%s", path, ".glusterfs/changelogs"); + ret = xlator_set_option (xl, "changelog-dir", changelog_basepath); + if (ret) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, "changelog"); + if (ret) + return -1; + + xl = volgen_graph_add (graph, "features/access-control", volname); + if (!xl) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, "acl"); + if (ret) + return -1; + + xl = volgen_graph_add (graph, "features/locks", volname); + if (!xl) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, "locks"); + if (ret) + return -1; + + xl = volgen_graph_add (graph, "performance/io-threads", volname); + if (!xl) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, "io-threads"); + if (ret) + return -1; + + ret = dict_get_int32 (volinfo->dict, "enable-pump", &pump); + if (ret == -ENOENT) + 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", volname); + if (!rbxl) + return -1; + + ptranst = glusterd_get_trans_type_rb (volinfo->transport_type); + if (NULL == ptranst) + return -1; + + if (username) { + ret = xlator_set_option (rbxl, "username", username); + if (ret) + return -1; + } + + if (password) { + ret = xlator_set_option (rbxl, "password", password); + if (ret) + return -1; + } + + ret = xlator_set_option (rbxl, "transport-type", ptranst); + GF_FREE (ptranst); + if (ret) + return -1; + + xl = volgen_graph_add_nolink (graph, "cluster/pump", "%s-pump", + 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; } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_METADATACHANGELOG, - &opt_metadatachangelog); - if (ret) { + xl = volgen_graph_add (graph, "features/index", volname); + if (!xl) + return -1; + + snprintf (index_basepath, sizeof (index_basepath), "%s/%s", + path, ".glusterfs/indices"); + ret = xlator_set_option (xl, "index-base", index_basepath); + if (ret) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, + "index"); + if (ret) + return -1; + + xl = volgen_graph_add (graph, "features/marker", volname); + if (!xl) + return -1; + + uuid_unparse (volinfo->volume_id, volume_id); + ret = xlator_set_option (xl, "volume-uuid", volume_id); + if (ret) + return -1; + get_vol_tstamp_file (tstamp_file, volinfo); + ret = xlator_set_option (xl, "timestamp-file", tstamp_file); + if (ret) + return -1; + + ret = check_and_add_debug_xl (graph, set_dict, volname, "marker"); + if (ret) + return -1; + + if (dict_get_str_boolean (set_dict, "features.read-only", 0) && + dict_get_str_boolean (set_dict, "features.worm",0)) { + gf_log (THIS->name, GF_LOG_ERROR, + "read-only and worm cannot be set together"); + ret = -1; goto out; } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_ENTRYCHANGELOG, - &opt_entrychangelog); - if (ret) { - goto out; + /* Check for read-only volume option, and add it to the graph */ + if (dict_get_str_boolean (set_dict, "features.read-only", 0) + || volinfo -> is_snap_volume) { + xl = volgen_graph_add (graph, "features/read-only", volname); + if (!xl) { + ret = -1; + goto out; + } } - ret = dict_get_str (dict, VOLGEN_REPLICATE_OPTION_STRICTREADDIR, - &opt_strictreaddir); - if (ret) { - goto out; + /* Check for worm volume option, and add it to the graph */ + if (dict_get_str_boolean (set_dict, "features.worm", 0)) { + xl = volgen_graph_add (graph, "features/worm", volname); + if (!xl) { + ret = -1; + goto out; + } } - for (i = 0; i < replicate_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, - subvolume_count); - len = strlen (tmp); - subvol_len += len; - subvolume_count++; + /* Check for compress volume option, and add it to the graph on server side */ + if (dict_get_str_boolean (set_dict, "features.compress", 0)) { + xl = volgen_graph_add (graph, "features/cdc", volname); + if (!xl) { + ret = -1; + goto out; + } + ret = dict_set_str (set_dict, "compress.mode", "server"); + if (ret) + goto out; } - subvolume_count = subvol_count; - subvol_len++; + xl = volgen_graph_add_as (graph, "debug/io-stats", path); + if (!xl) + 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; + xl = volgen_graph_add (graph, "protocol/server", volname); + if (!xl) + return -1; + ret = xlator_set_option (xl, "transport-type", transt); + if (ret) + return -1; + + /*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 (THIS->options, "transport.socket.bind-address")) { + ret = xlator_set_option (xl, "transport.socket.bind-address", + brickinfo->hostname); + if (ret) + return -1; } - for (i = 0; i < replicate_count ; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, - subvolume_count); - strncat (subvol_str, tmp, strlen (tmp)); - subvolume_count++; + if (username) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "auth.login.%s.allow", path); + + ret = xlator_set_option (xl, key, username); + if (ret) + return -1; } - 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); + if (password) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "auth.login.%s.password", + username); + ret = xlator_set_option (xl, key, password); + if (ret) + return -1; + } - ret = 0; + 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); -out: - if (subvol_str) - GF_FREE (subvol_str); + out: return ret; } + +/* builds a graph for server role , with option overrides in mod_dict */ static int -__write_stripe_xlator (FILE *file, dict_t *dict, - char *subvolume, - int stripe_count, - int subvol_count, - int count) +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); +} + +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; + + GF_ASSERT (param); + volinfo = param; + + if (strcmp (vme->option, "!perf") != 0) + return 0; + + if (gf_string2boolean (vme->value, &enabled) == -1) + return -1; + if (!enabled) + return 0; + + /* 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 (volgen_graph_add (graph, vme->voltype, volinfo->volname)) + return 0; + else + return -1; +} + +static int +nfsperfxl_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; - - const 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"; - - subvolume_count = subvol_count; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } + gf_boolean_t enabled = _gf_false; - ret = dict_get_str (dict, VOLGEN_STRIPE_OPTION_BLOCKSIZE, - &opt_blocksize); - if (ret) { + volname = param; + + 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; +} + +#if (HAVE_LIB_XML) +static int +end_sethelp_xml_doc (xmlTextWriterPtr writer) +{ + int ret = -1; + + ret = xmlTextWriterEndElement(writer); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not end an " + "xmlElemetnt"); + ret = -1; goto out; } - - ret = dict_get_str (dict, VOLGEN_STRIPE_OPTION_USEXATTR, - &opt_usexattr); - if (ret) { + ret = xmlTextWriterEndDocument (writer); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not end an " + "xmlDocument"); + ret = -1; goto out; } + ret = 0; + out: + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} - for (i = 0; i < stripe_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, subvolume_count); - len = strlen (tmp); - subvol_len += len; - subvolume_count++; +static int +init_sethelp_xml_doc (xmlTextWriterPtr *writer, xmlBufferPtr *buf) +{ + int ret; + + *buf = xmlBufferCreateSize (8192); + if (buf == NULL) { + gf_log ("glusterd", GF_LOG_ERROR, "Error creating the xml " + "buffer"); + ret = -1; + goto out; } - subvolume_count = subvol_count; - subvol_len++; + xmlBufferSetAllocationScheme (*buf,XML_BUFFER_ALLOC_DOUBLEIT); - subvol_str = GF_CALLOC (1, subvol_len, gf_gld_mt_char); - if (!subvol_str) { - gf_log ("glusterd", GF_LOG_ERROR, - "Out of memory"); + *writer = xmlNewTextWriterMemory(*buf, 0); + if (writer == NULL) { + gf_log ("glusterd", GF_LOG_ERROR, " Error creating the xml " + "writer"); ret = -1; 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 = xmlTextWriterStartDocument(*writer, "1.0", "UTF-8", "yes"); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Error While starting the " + "xmlDoc"); + goto out; } - fprintf (file, stripe_str, - volname, - "stripe", - count, - opt_blocksize, - opt_usexattr, - subvol_str); + ret = xmlTextWriterStartElement(*writer, (xmlChar *)"options"); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not create an " + "xmlElemetnt"); + ret = -1; + goto out; + } ret = 0; -out: - if (subvol_str) - GF_FREE (subvol_str); + out: + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); return ret; - + } static int -__write_distribute_xlator (FILE *file, dict_t *dict, - char *subvolume, - int dist_count) -{ - 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; - - const 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; - } +xml_add_volset_element (xmlTextWriterPtr writer, const char *name, + const char *def_val, const char *dscrpt) +{ - ret = dict_get_str (dict, VOLGEN_DHT_OPTION_LOOKUPUNHASH, - &opt_lookupunhash); - if (ret) { + int ret = -1; + + GF_ASSERT (name); + + ret = xmlTextWriterStartElement(writer, (xmlChar *) "option"); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not create an " + "xmlElemetnt"); + ret = -1; goto out; } - ret = dict_get_str (dict, VOLGEN_DHT_OPTION_MINFREEDISK, - &opt_minfreedisk); - if (ret) { + ret = xmlTextWriterWriteFormatElement(writer, (xmlChar*)"defaultValue", + "%s", def_val); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not create an " + "xmlElemetnt"); + ret = -1; goto out; } - ret = dict_get_str (dict, VOLGEN_DHT_OPTION_UNHASHSTICKY, - &opt_unhashsticky); - if (ret) { + ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"description", + "%s", dscrpt ); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not create an " + "xmlElemetnt"); + ret = -1; goto out; } - for (i = 0; i < dist_count; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, i); - len = strlen (tmp); - subvol_len += len; + ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *) "name", "%s", + name); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not create an " + "xmlElemetnt"); + ret = -1; + goto out; } - 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 = xmlTextWriterEndElement(writer); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, "Could not end an " + "xmlElemetnt"); ret = -1; goto out; } - for (i = 0; i < dist_count ; i++) { - snprintf (tmp, 4096, "%s-%d ", subvolume, i); - strncat (subvol_str, tmp, strlen (tmp)); + ret = 0; + out: + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + return ret; + +} + +#endif + +static 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); + else if (!strcmp (vme->key, NFS_DISABLE_MAP_KEY)) + *key = gf_strdup (NFS_DISABLE_OPT_KEY); + 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_log ("glusterd", GF_LOG_ERROR, "Wrong entry found in " + "glusterd_volopt_map entry %s", vme->key); + else + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); - fprintf (file, dht_str, - volname, - "dht", - opt_lookupunhash, - opt_minfreedisk, - opt_unhashsticky, - subvol_str); + return ret; +} +static void +_free_xlator_opt_key (char *key) +{ + GF_ASSERT (key); - ret = 0; + if (!strcmp (key, AUTH_ALLOW_OPT_KEY) || + !strcmp (key, AUTH_REJECT_OPT_KEY) || + !strcmp (key, NFS_DISABLE_OPT_KEY)) + GF_FREE (key); + return; +} + +int +glusterd_get_volopt_content (dict_t * ctx, gf_boolean_t xml_out) +{ + void *dl_handle = NULL; + volume_opt_list_t vol_opt_handle = {{0},}; + char *key = NULL; + struct volopt_map_entry *vme = NULL; + int ret = -1; + char *def_val = NULL; + char *descr = NULL; + char output_string[25600] = {0, }; + char *output = NULL; + char tmp_str[2048] = {0, }; +#if (HAVE_LIB_XML) + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + + if (xml_out) { + ret = init_sethelp_xml_doc (&writer, &buf); + if (ret) /*logging done in init_xml_lib*/ + goto out; + } +#endif + + INIT_LIST_HEAD (&vol_opt_handle.list); + + for (vme = &glusterd_volopt_map[0]; vme->key; vme++) { + + if ((vme->type == NO_DOC) || (vme->type == GLOBAL_NO_DOC)) + continue; + + if (vme->description) { + descr = vme->description; + def_val = vme->value; + } else { + if (_get_xlator_opt_key_from_vme (vme, &key)) { + gf_log ("glusterd", GF_LOG_DEBUG, "Failed to " + "get %s key from volume option entry", + vme->key); + goto out; /*Some error while geting key*/ + } + + ret = xlator_volopt_dynload (vme->voltype, + &dl_handle, + &vol_opt_handle); + + if (ret) { + gf_log ("glusterd", GF_LOG_DEBUG, + "xlator_volopt_dynload error(%d)", ret); + ret = 0; + goto cont; + } + + ret = xlator_option_info_list (&vol_opt_handle, key, + &def_val, &descr); + if (ret) { /*Swallow Error i.e if option not found*/ + gf_log ("glusterd", GF_LOG_DEBUG, + "Failed to get option for %s key", key); + ret = 0; + goto cont; + } + } + + if (xml_out) { +#if (HAVE_LIB_XML) + if (xml_add_volset_element (writer,vme->key, + def_val, descr)) { + ret = -1; + goto cont; + } +#else + gf_log ("glusterd", GF_LOG_ERROR, "Libxml not present"); +#endif + } else { + snprintf (tmp_str, sizeof (tmp_str), "Option: %s\nDefault " + "Value: %s\nDescription: %s\n\n", + vme->key, def_val, descr); + strcat (output_string, tmp_str); + } +cont: + if (dl_handle) { + dlclose (dl_handle); + dl_handle = NULL; + vol_opt_handle.given_opt = NULL; + } + if (key) { + _free_xlator_opt_key (key); + key = NULL; + } + if (ret) + goto out; + } + +#if (HAVE_LIB_XML) + if ((xml_out) && + (ret = end_sethelp_xml_doc (writer))) + goto out; +#else + if (xml_out) + gf_log ("glusterd", GF_LOG_ERROR, "Libxml not present"); +#endif + + if (!xml_out) + output = gf_strdup (output_string); + else +#if (HAVE_LIB_XML) + output = gf_strdup ((char *)buf->content); +#else + gf_log ("glusterd", GF_LOG_ERROR, "Libxml not present"); +#endif + + if (NULL == output) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (ctx, "help-str", output); out: - if (subvol_str) - GF_FREE (subvol_str); + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); return ret; + } static int -__write_wb_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - 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; - - const 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"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +volgen_graph_build_clients (volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) +{ + int i = 0; + int ret = -1; + uint32_t client_type = GF_CLIENT_OTHER; + char transt[16] = {0,}; + char *volname = NULL; + char *str = NULL; + glusterd_brickinfo_t *brick = NULL; + xlator_t *xl = NULL; + char *ssl_str = NULL; + gf_boolean_t ssl_bool; - ret = dict_get_str (dict, VOLGEN_WB_OPTION_FLUSHBEHIND, - &opt_flushbehind); - if (ret) { + volname = volinfo->volname; + + if (volinfo->brick_count == 0) { + gf_log ("", GF_LOG_ERROR, + "volume inconsistency: brick count is 0"); goto out; } - ret = dict_get_str (dict, VOLGEN_WB_OPTION_CACHESIZE, - &opt_cachesize); - if (ret) { + if ((volinfo->dist_leaf_count < volinfo->brick_count) && + ((volinfo->brick_count % volinfo->dist_leaf_count) != 0)) { + gf_log ("", GF_LOG_ERROR, + "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; } - ret = dict_get_str (dict, VOLGEN_WB_OPTION_DISABLENBYTES, - &opt_disablenbytes); - if (ret) { - goto out; + get_transport_type (volinfo, set_dict, transt, _gf_false); + + if (!strcmp (transt, "tcp,rdma")) + strcpy (transt, "tcp"); + + i = 0; + ret = -1; + list_for_each_entry (brick, &volinfo->bricks, brick_list) { + ret = -1; + xl = volgen_graph_add_nolink (graph, "protocol/client", + "%s-client-%d", volname, i); + if (!xl) + goto out; + ret = xlator_set_option (xl, "remote-host", brick->hostname); + if (ret) + goto out; + ret = xlator_set_option (xl, "remote-subvolume", brick->path); + if (ret) + goto out; + ret = xlator_set_option (xl, "transport-type", transt); + if (ret) + goto out; + + ret = dict_get_uint32 (set_dict, "trusted-client", + &client_type); + + if (!ret && client_type == GF_CLIENT_TRUSTED) { + str = NULL; + str = glusterd_auth_get_username (volinfo); + if (str) { + ret = xlator_set_option (xl, "username", + str); + if (ret) + goto out; + } + + str = glusterd_auth_get_password (volinfo); + if (str) { + ret = xlator_set_option (xl, "password", + str); + if (ret) + goto out; + } + } + + if (dict_get_str(set_dict,"client.ssl",&ssl_str) == 0) { + if (gf_string2boolean(ssl_str,&ssl_bool) == 0) { + if (ssl_bool) { + ret = xlator_set_option(xl, + "transport.socket.ssl-enabled", + "true"); + if (ret) { + goto out; + } + } + } + } + + i++; } - ret = dict_get_str (dict, VOLGEN_WB_OPTION_OSYNC, - &opt_osync); - if (ret) { + if (i != volinfo->brick_count) { + gf_log ("", GF_LOG_ERROR, + "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; +} - ret = dict_get_str (dict, VOLGEN_WB_OPTION_TRICKLINGWRITES, - &opt_tricklingwrites); - if (ret) { +static int +volgen_graph_build_clusters (volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, char *xl_type, + char *xl_namefmt, size_t child_count, + size_t sub_count) +{ + int i = 0; + int j = 0; + xlator_t *txl = NULL; + xlator_t *xl = NULL; + xlator_t *trav = NULL; + char *volname = NULL; + int ret = -1; + + if (child_count == 0) goto out; - } + volname = volinfo->volname; + txl = first_of (graph); + for (trav = txl; --child_count; trav = trav->next); + for (;; trav = trav->prev) { + if ((i % sub_count) == 0) { + xl = volgen_graph_add_nolink (graph, xl_type, + xl_namefmt, volname, j); + if (!xl) { + ret = -1; + goto out; + } + j++; + } - fprintf (file, dht_str, - volname, - "write-behind", - opt_flushbehind, - opt_cachesize, - opt_disablenbytes, - opt_osync, - opt_tricklingwrites, - subvolume); + ret = volgen_xlator_link (xl, trav); + if (ret) + goto out; + if (trav == txl) + break; - ret = 0; + i++; + } + ret = j; out: return ret; } -static int -__write_ra_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - char *volname = NULL; - char *opt_atime = NULL; - char *opt_pagecount = 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"; - - ret = dict_get_str (dict, "volname", &volname); +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_option (xl, "remote-host", &hostname); if (ret) { + GF_ASSERT (0); + gf_log ("glusterd", GF_LOG_ERROR, "Failed to get remote-host " + "from client %s", xl->name); goto out; } - - ret = dict_get_str (dict, VOLGEN_RA_OPTION_ATIME, - &opt_atime); + ret = xlator_get_option (xl, "remote-subvolume", &path); if (ret) { + GF_ASSERT (0); + gf_log ("glusterd", GF_LOG_ERROR, "Failed to get remote-host " + "from client %s", xl->name); goto out; } - ret = dict_get_str (dict, VOLGEN_RA_OPTION_PAGECOUNT, - &opt_pagecount); - if (ret) { + 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; } - fprintf (file, ra_str, - volname, - "read-ahead", - opt_atime, - opt_pagecount, - subvolume); + 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 decommissioned; +} - ret = 0; +static int +_graph_get_decommissioned_children (xlator_t *dht, glusterd_volinfo_t *volinfo, + char **children) +{ + 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; } static int -__write_iocache_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - 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; - - const 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"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { +volgen_graph_build_dht_cluster (volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, size_t child_count) +{ + int32_t clusters = 0; + int ret = -1; + char *decommissioned_children = NULL; + xlator_t *dht = NULL; + char *voltype = "cluster/distribute"; + + /* NUFA and Switch section */ + if (dict_get_str_boolean (volinfo->dict, "cluster.nufa", 0) && + dict_get_str_boolean (volinfo->dict, "cluster.switch", 0)) { + gf_log (THIS->name, GF_LOG_ERROR, + "nufa and switch cannot be set together"); + ret = -1; goto out; } - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_PRIORITY, - &opt_priority); - if (ret) { - goto out; - } + /* Check for NUFA volume option, and change the voltype */ + if (dict_get_str_boolean (volinfo->dict, "cluster.nufa", 0)) + voltype = "cluster/nufa"; - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_TIMEOUT, - &opt_timeout); - if (ret) { + /* Check for switch volume option, and change the voltype */ + if (dict_get_str_boolean (volinfo->dict, "cluster.switch", 0)) + voltype = "cluster/switch"; + + clusters = volgen_graph_build_clusters (graph, volinfo, + voltype, + "%s-dht", + child_count, + child_count); + if (clusters < 0) goto out; - } - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_CACHESIZE, - &opt_cachesize); - if (ret) { + dht = first_of (graph); + ret = _graph_get_decommissioned_children (dht, volinfo, + &decommissioned_children); + if (ret) goto out; + if (decommissioned_children) { + ret = xlator_set_option (dht, "decommissioned-bricks", + decommissioned_children); + if (ret) + goto out; } + ret = 0; +out: + GF_FREE (decommissioned_children); + return ret; +} - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_MINFILESIZE, - &opt_minfilesize); - if (ret) { +static int +volume_volgen_graph_build_clusters (volgen_graph_t *graph, + glusterd_volinfo_t *volinfo) +{ + char *replicate_args[] = {"cluster/replicate", + "%s-replicate-%d"}; + char *stripe_args[] = {"cluster/stripe", + "%s-stripe-%d"}; + int rclusters = 0; + int clusters = 0; + int dist_count = 0; + int ret = -1; + + 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_clusters (graph, volinfo, + replicate_args[0], + replicate_args[1], + volinfo->brick_count, + volinfo->replica_count); + if (clusters < 0) + goto out; + break; + case GF_CLUSTER_TYPE_STRIPE: + clusters = volgen_graph_build_clusters (graph, volinfo, + stripe_args[0], + stripe_args[1], + volinfo->brick_count, + volinfo->stripe_count); + if (clusters < 0) + goto out; + break; + case GF_CLUSTER_TYPE_STRIPE_REPLICATE: + /* Replicate after the clients, then stripe */ + if (volinfo->replica_count == 0) + goto out; + clusters = volgen_graph_build_clusters (graph, volinfo, + replicate_args[0], + replicate_args[1], + volinfo->brick_count, + volinfo->replica_count); + if (clusters < 0) + goto out; + + rclusters = volinfo->brick_count / volinfo->replica_count; + GF_ASSERT (rclusters == clusters); + clusters = volgen_graph_build_clusters (graph, volinfo, + stripe_args[0], + stripe_args[1], + rclusters, + volinfo->stripe_count); + if (clusters < 0) + goto out; + break; + default: + gf_log ("", GF_LOG_ERROR, "volume inconsistency: " + "unrecognized clustering type"); goto out; } - ret = dict_get_str (dict, VOLGEN_IOCACHE_OPTION_MAXFILESIZE, - &opt_maxfilesize); - if (ret) { +build_distribute: + dist_count = volinfo->brick_count / volinfo->dist_leaf_count; + if (!dist_count) { + ret = -1; goto out; } - fprintf (file, iocache_str, - volname, - "io-cache", - opt_priority, - opt_timeout, - opt_cachesize, - opt_minfilesize, - opt_maxfilesize, - subvolume); - + ret = volgen_graph_build_dht_cluster (graph, volinfo, + dist_count); + if (ret == -1) + goto out; ret = 0; - out: return ret; } +static int client_graph_set_perf_options(volgen_graph_t *graph, + glusterd_volinfo_t *volinfo, + dict_t *set_dict) +{ + data_t *tmp_data = NULL; + char *volname = NULL; + + /* + * Logic to make sure NFS doesn't have performance translators by + * default for a volume + */ + volname = volinfo->volname; + tmp_data = dict_get (set_dict, "nfs-volume-file"); + if (!tmp_data) + return volgen_graph_set_options_generic(graph, set_dict, + volname, + &perfxl_option_handler); + else + return volgen_graph_set_options_generic(graph, set_dict, + volname, + &nfsperfxl_option_handler); +} + static int -__write_qr_xlator (FILE *file, dict_t *dict, - char *subvolume) -{ - char *volname = NULL; - char *opt_priority = NULL; - char *opt_timeout = NULL; - char *opt_cachesize = NULL; - char *opt_maxfilesize = NULL; - int ret = -1; - - 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"; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) { +client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *set_dict, void *param) +{ + int ret = 0; + xlator_t *xl = NULL; + char *volname = NULL; + + volname = volinfo->volname; + ret = volgen_graph_build_clients (graph, volinfo, set_dict, param); + if (ret) goto out; - } - ret = dict_get_str (dict, VOLGEN_QR_OPTION_PRIORITY, - &opt_priority); - if (ret) { + ret = volume_volgen_graph_build_clusters (graph, volinfo); + if (ret == -1) goto out; + + /* Check for compress volume option, and add it to the graph on client side */ + if (dict_get_str_boolean (set_dict, "features.compress", 0)) { + xl = volgen_graph_add (graph, "features/cdc", volname); + if (!xl) { + ret = -1; + goto out; + } + ret = dict_set_str (set_dict, "compress.mode", "client"); + if (ret) + goto out; + } - ret = dict_get_str (dict, VOLGEN_QR_OPTION_TIMEOUT, - &opt_timeout); - if (ret) { + ret = glusterd_volinfo_get_boolean (volinfo, "features.encryption"); + if (ret == -1) goto out; + if (ret) { + xl = volgen_graph_add (graph, "encryption/crypt", volname); + + if (!xl) { + ret = -1; + goto out; + } } - ret = dict_get_str (dict, VOLGEN_QR_OPTION_CACHESIZE, - &opt_cachesize); - if (ret) { + 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; + } } - ret = dict_get_str (dict, VOLGEN_QR_OPTION_MAXFILESIZE, - &opt_maxfilesize); - if (ret) { + + ret = glusterd_volinfo_get_boolean (volinfo, "features.file-snapshot"); + if (ret == -1) goto out; + if (ret) { + xl = volgen_graph_add (graph, "features/qemu-block", volname); + + if (!xl) { + ret = -1; + goto out; + } } - fprintf (file, qr_str, - volname, - "quick-read", - opt_priority, - opt_timeout, - opt_cachesize, - opt_maxfilesize, - subvolume); + ret = client_graph_set_perf_options(graph, volinfo, set_dict); + if (ret) + goto out; - ret = 0; + /* add debug translators depending on the options */ + ret = check_and_add_debug_xl (graph, set_dict, volname, + "client"); + if (ret) + return -1; + + ret = -1; + xl = volgen_graph_add_as (graph, "debug/io-stats", volname); + if (!xl) + goto out; + + ret = volgen_graph_set_options_generic (graph, set_dict, "client", + &loglevel_option_handler); + + if (ret) + gf_log (THIS->name, GF_LOG_WARNING, "changing client log level" + " failed"); + ret = volgen_graph_set_options_generic (graph, set_dict, "client", + &sys_loglevel_option_handler); + if (ret) + gf_log (THIS->name, GF_LOG_WARNING, "changing client syslog " + "level failed"); out: return ret; } + +/* builds a graph for client role , with option overrides in mod_dict */ static int -__write_statprefetch_xlator (FILE *file, dict_t *dict, - char *subvolume) +build_client_graph (volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + dict_t *mod_dict) { - char *volname = NULL; - int ret = -1; + return build_graph_generic (graph, volinfo, mod_dict, NULL, + &client_graph_builder); +} - const char *statprefetch_str = "volume %s\n" - " type performance/stat-prefetch\n" - " subvolumes %s\n" - "end-volume\n\n"; +char *gd_shd_options[] = { + "!self-heal-daemon", + "!heal-timeout", + NULL +}; - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; - } +char* +gd_get_matching_option (char **options, char *option) +{ + while (*options && strcmp (*options, option)) + options++; + return *options; +} - fprintf (file, statprefetch_str, - volname, - subvolume); +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; - ret = 0; + 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; } static int -generate_server_volfile (glusterd_brickinfo_t *brickinfo, - dict_t *dict, - const char *filename) +nfs_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; + xlator_t *xl = NULL; + char *aa = NULL; + int ret = 0; + glusterd_volinfo_t *volinfo = NULL; - GF_ASSERT (filename); + volinfo = param; - file = fopen (filename, "w+"); - if (!file) { - gf_log ("", GF_LOG_DEBUG, - "Could not open file %s", filename); - ret = -1; - goto out; + xl = first_of (graph); + +/* if (vme->type == GLOBAL_DOC || vme->type == GLOBAL_NO_DOC) { + + ret = xlator_set_option (xl, vme->key, vme->value); + }*/ + if (!volinfo || (volinfo->volname[0] == '\0')) + return 0; + + if (! strcmp (vme->option, "!rpc-auth.addr.*.allow")) { + ret = gf_asprintf (&aa, "rpc-auth.addr.%s.allow", + volinfo->volname); + + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - ret = dict_get_str (dict, "volname", &volname); - if (ret) { - goto out; + if (! strcmp (vme->option, "!rpc-auth.addr.*.reject")) { + ret = gf_asprintf (&aa, "rpc-auth.addr.%s.reject", + volinfo->volname); + + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - /* Call functions in the same order - as you'd call if you were manually - writing a volfile top-down - */ + if (! strcmp (vme->option, "!rpc-auth.auth-unix.*")) { + ret = gf_asprintf (&aa, "rpc-auth.auth-unix.%s", + volinfo->volname); - ret = __write_posix_xlator (file, dict, brickinfo->path); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } + if (! strcmp (vme->option, "!rpc-auth.auth-null.*")) { + ret = gf_asprintf (&aa, "rpc-auth.auth-null.%s", + volinfo->volname); - VOLGEN_GENERATE_VOLNAME (subvol, volname, "posix"); + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } - ret = __write_access_control_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + if (ret) + return -1; } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "access-control"); + if (! strcmp (vme->option, "!nfs3.*.trusted-sync")) { + ret = gf_asprintf (&aa, "nfs3.%s.trusted-sync", + volinfo->volname); - ret = __write_locks_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "locks"); + if (! strcmp (vme->option, "!nfs3.*.trusted-write")) { + ret = gf_asprintf (&aa, "nfs3.%s.trusted-write", + volinfo->volname); - ret = __write_replace_brick_xlator (file, dict); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - ret = __write_pump_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + if (! strcmp (vme->option, "!nfs3.*.volume-access")) { + ret = gf_asprintf (&aa, "nfs3.%s.volume-access", + volinfo->volname); + + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "pump"); + if (! strcmp (vme->option, "!nfs3.*.export-dir")) { + ret = gf_asprintf (&aa, "nfs3.%s.export-dir", + volinfo->volname); - ret = dict_set_str (dict, "export-path", brickinfo->path); - if (ret) { - goto out; + if (ret != -1) { + ret = gf_canonicalize_path (vme->value); + if (ret) + return -1; + + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - ret = __write_iothreads_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + + + if (! strcmp (vme->option, "!rpc-auth.ports.*.insecure")) { + ret = gf_asprintf (&aa, "rpc-auth.ports.%s.insecure", + volinfo->volname); + + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; } - ret = __write_server_xlator (file, dict, brickinfo->path); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + + if (! strcmp (vme->option, "!nfs-disable")) { + ret = gf_asprintf (&aa, "nfs.%s.disable", + volinfo->volname); + + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + + if (ret) + return -1; + } + + if ( (strcmp (vme->voltype, "nfs/server") == 0) && + (vme->option && vme->option[0]!='!') ) { + ret = xlator_set_option (xl, vme->option, vme->value); + if (ret) + return -1; } - fclose (file); - file = NULL; -out: - return ret; + /*key = strchr (vme->key, '.') + 1; + + for (trav = xl->children; trav; trav = trav->next) { + ret = gf_asprintf (&aa, "auth.addr.%s.%s", trav->xlator->name, + key); + if (ret != -1) { + ret = xlator_set_option (xl, aa, vme->value); + GF_FREE (aa); + } + if (ret) + return -1; + }*/ + + return 0; } static int -generate_client_volfile (glusterd_volinfo_t *volinfo, char *filename) -{ - FILE *file = NULL; - dict_t *dict = NULL; - char *volname = NULL; - glusterd_brickinfo_t *brick = NULL; - 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; - - GF_ASSERT (filename); +volgen_graph_set_iam_shd (volgen_graph_t *graph) +{ + xlator_t *trav; + int ret = 0; - 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; - } + for (trav = first_of (graph); trav; trav = trav->next) { + if (strcmp (trav->type, "cluster/replicate") != 0) + continue; - } 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 = xlator_set_option (trav, "iam-self-heal-daemon", "yes"); + if (ret) + break; } + return ret; +} +static int +build_shd_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; + gf_boolean_t valid_config = _gf_false; + xlator_t *iostxl = NULL; + int rclusters = 0; + int replica_count = 0; + gf_boolean_t graph_check = _gf_false; - file = fopen (filename, "w+"); - if (!file) { - gf_log ("", GF_LOG_DEBUG, - "Could not open file %s", filename); + this = THIS; + priv = this->private; + + set_dict = dict_new (); + if (!set_dict) { + ret = -ENOMEM; + goto out; + } + + graph_check = dict_get_str_boolean (mod_dict, "graph-check", 0); + iostxl = volgen_graph_add_as (graph, "debug/io-stats", "glustershd"); + if (!iostxl) { ret = -1; goto out; } - /* Call functions in the same order - as you'd call if you were manually - writing a volfile top-down - */ + list_for_each_entry (voliter, &priv->volumes, vol_list) { + if (!graph_check && + (voliter->status != GLUSTERD_STATUS_STARTED)) + continue; + + if (!glusterd_is_volume_replicate (voliter)) + continue; - count = 0; + replica_count = voliter->replica_count; - list_for_each_entry (brick, &volinfo->bricks, brick_list) { + valid_config = _gf_true; - ret = __write_client_xlator (file, dict, brick->path, - brick->hostname, count); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); + ret = dict_set_str (set_dict, "cluster.self-heal-daemon", "on"); + if (ret) + goto out; + + ret = dict_set_uint32 (set_dict, "trusted-client", + GF_CLIENT_TRUSTED); + if (ret) + goto out; + + dict_copy (voliter->dict, set_dict); + if (mod_dict) + dict_copy (mod_dict, set_dict); + + memset (&cgraph, 0, sizeof (cgraph)); + ret = volgen_graph_build_clients (&cgraph, voliter, set_dict, + NULL); + if (ret) + goto out; + + rclusters = volgen_graph_build_clusters (&cgraph, voliter, + "cluster/replicate", + "%s-replicate-%d", + voliter->brick_count, + replica_count); + if (rclusters < 0) { + ret = -1; goto out; } - count++; + ret = volgen_graph_set_options_generic (&cgraph, set_dict, voliter, + shd_option_handler); + if (ret) + goto out; + + ret = volgen_graph_set_iam_shd (&cgraph); + if (ret) + goto out; + + ret = volgen_graph_merge_sub (graph, &cgraph, rclusters); + if (ret) + goto out; + + ret = volgen_graph_set_options_generic (graph, set_dict, + "client", + &loglevel_option_handler); + + if (ret) + gf_log (THIS->name, GF_LOG_WARNING, "changing loglevel " + "of self-heal daemon failed"); + + ret = volgen_graph_set_options_generic (graph, set_dict, + "client", + &sys_loglevel_option_handler); + if (ret) + gf_log (THIS->name, GF_LOG_WARNING, "changing syslog " + "level of self-heal daemon failed"); + + ret = dict_reset (set_dict); + if (ret) + goto out; } +out: + if (set_dict) + dict_unref (set_dict); + if (!valid_config) + ret = -EINVAL; + return ret; +} - if (stripe_count && replicate_count) { - gf_log ("", GF_LOG_DEBUG, - "Striped Replicate config not allowed"); +/* builds a graph for nfs server role, with option overrides in mod_dict */ +static int +build_nfs_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; + 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_log ("", GF_LOG_ERROR, "Out of memory"); + return -1; + } + + nfsxl = volgen_graph_add_as (graph, "nfs/server", "nfs-server"); + if (!nfsxl) { ret = -1; goto out; } + ret = xlator_set_option (nfsxl, "nfs.dynamic-volumes", "on"); + if (ret) + goto out; - if (replicate_count > 1) { - subvol_count = 0; - for (i = 0; i < dist_count; i++) { + ret = xlator_set_option (nfsxl, "nfs.nlm", "on"); + if (ret) + goto out; - VOLGEN_GENERATE_VOLNAME (subvol, volname, "client"); + ret = xlator_set_option (nfsxl, "nfs.drc", "on"); + if (ret) + goto out; - ret = __write_replicate_xlator (file, dict, subvol, - replicate_count, - subvol_count, - i); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Count not write xlator"); - goto out; - } + 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", 0)) + continue; - subvol_count += replicate_count; + ret = gf_asprintf (&skey, "rpc-auth.addr.%s.allow", + voliter->volname); + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, "Out of memory"); + goto out; + } + ret = xlator_set_option (nfsxl, skey, "*"); + GF_FREE (skey); + if (ret) + goto out; + ret = gf_asprintf (&skey, "nfs3.%s.volume-id", + voliter->volname); + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, "Out of memory"); + goto out; } - } + ret = xlator_set_option (nfsxl, skey, uuid_utoa (voliter->volume_id)); + GF_FREE (skey); + if (ret) + goto out; - if (stripe_count > 1) { - subvol_count = 0; - for (i = 0; i < dist_count; i++) { + /* If both RDMA and TCP are the transport_type, use RDMA + for NFS client protocols */ + 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); - VOLGEN_GENERATE_VOLNAME (subvol, volname, "client"); + ret = dict_set_str (set_dict, "performance.stat-prefetch", "off"); + if (ret) + goto out; - ret = __write_stripe_xlator (file, dict, subvol, - stripe_count, - subvol_count, - i); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Count not write xlator"); - goto out; - } + ret = dict_set_str (set_dict, "performance.client-io-threads", + "off"); + if (ret) + goto out; + + ret = dict_set_str (set_dict, "client-transport-type", + nfs_xprt); + if (ret) + goto out; - subvol_count += stripe_count; + ret = dict_set_uint32 (set_dict, "trusted-client", + GF_CLIENT_TRUSTED); + if (ret) + goto out; + + ret = dict_set_str (set_dict, "nfs-volume-file", "yes"); + if (ret) + goto out; + + if (mod_dict && (data = dict_get (mod_dict, "volume-name"))) { + volname = data->data; + if (strcmp (volname, voliter->volname) == 0) + dict_copy (mod_dict, set_dict); } - } + ret = build_client_graph (&cgraph, voliter, set_dict); + if (ret) + goto out; - if (dist_count > 1) { - if (replicate_count) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, - "replicate"); - } else if (stripe_count) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, - "stripe"); + if (mod_dict) { + dict_copy (mod_dict, set_dict); + ret = volgen_graph_set_options_generic (&cgraph, set_dict, voliter, + basic_option_handler); } else { - VOLGEN_GENERATE_VOLNAME (subvol, volname, - "client"); + ret = volgen_graph_set_options_generic (&cgraph, voliter->dict, voliter, + basic_option_handler); } + if (ret) + goto out; - ret = __write_distribute_xlator (file, - dict, - subvol, - dist_count); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Count not write xlator"); + ret = volgen_graph_merge_sub (graph, &cgraph, 1); + if (ret) + goto out; + ret = dict_reset (set_dict); + if (ret) goto out; - } } + list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (dist_count > 1) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "dht"); - ret = __write_wb_xlator (file, dict, subvol); - } - else if (replicate_count > 1) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "replicate-0"); - ret = __write_wb_xlator (file, dict, subvol); - } - else if (stripe_count > 1) { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "stripe-0"); - ret = __write_wb_xlator (file, dict, subvol); - } - else { - VOLGEN_GENERATE_VOLNAME (subvol, volname, "client-0"); - ret = __write_wb_xlator (file, dict, subvol); - } - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; + 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 (ret) + gf_log ("glusterd", GF_LOG_WARNING, "Could not set " + "vol-options for the volume %s", voliter->volname); } + out: + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + dict_destroy (set_dict); - VOLGEN_GENERATE_VOLNAME (subvol, volname, "write-behind"); - ret = __write_ra_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } + return ret; +} - VOLGEN_GENERATE_VOLNAME (subvol, volname, "read-ahead"); - ret = __write_iocache_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "io-cache"); - ret = __write_qr_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } - VOLGEN_GENERATE_VOLNAME (subvol, volname, "quick-read"); - ret = __write_statprefetch_xlator (file, dict, subvol); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "Could not write xlator"); - goto out; - } - fclose (file); - file = NULL; +/**************************** + * + * Volume generation interface + * + ****************************/ -out: - return ret; -} -static char * -get_brick_filename (glusterd_volinfo_t *volinfo, +static void +get_brick_filepath (char *filename, glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo) { char path[PATH_MAX] = {0,}; - char *ret = NULL; char brick[PATH_MAX] = {0,}; - char *filename = NULL; + glusterd_conf_t *priv = NULL; - filename = GF_CALLOC (1, PATH_MAX, gf_gld_mt_char); - if (!filename) - goto out; + priv = THIS->private; GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick); - VOLGEN_GET_VOLUME_DIR (path, volinfo); + GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv); snprintf (filename, PATH_MAX, "%s/%s.%s.%s.vol", path, volinfo->volname, brickinfo->hostname, brick); - - ret = filename; -out: - return ret; } -char * -glusterd_get_nfs_filepath () +gf_boolean_t +glusterd_is_valid_volfpath (char *volname, char *brick) { - char path[PATH_MAX] = {0,}; - char *ret = NULL; - char *filepath = NULL; + char volfpath[PATH_MAX] = {0,}; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_volinfo_t *volinfo = NULL; + int32_t ret = 0; + xlator_t *this = NULL; - filepath = GF_CALLOC (1, PATH_MAX, gf_common_mt_char); - if (!filepath) { - gf_log ("", GF_LOG_ERROR, "Unable to allocate nfs file path"); + this = THIS; + GF_ASSERT (this); + + ret = glusterd_brickinfo_new_from_brick (brick, &brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Failed to create brickinfo" + " for brick %s", brick ); + ret = 0; goto out; } + ret = glusterd_volinfo_new (&volinfo); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Failed to create volinfo"); + ret = 0; + goto out; + } + strncpy (volinfo->volname, volname, sizeof (volinfo->volname)); + get_brick_filepath (volfpath, volinfo, brickinfo); - VOLGEN_GET_NFS_DIR (path); - - snprintf (filepath, PATH_MAX, "%s/nfs-server.vol", path); + ret = (strlen (volfpath) < _POSIX_PATH_MAX); - ret = filepath; out: + if (brickinfo) + glusterd_brickinfo_delete (brickinfo); + if (volinfo) + glusterd_volinfo_delete (volinfo); return ret; } - -static char * -get_client_filepath (glusterd_volinfo_t *volinfo) +static int +glusterd_generate_brick_volfile (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo) { - char path[PATH_MAX] = {0,}; - char *ret = NULL; - char *filename = NULL; + volgen_graph_t graph = {0,}; + char filename[PATH_MAX] = {0,}; + int ret = -1; - filename = GF_CALLOC (1, PATH_MAX, gf_gld_mt_char); - if (!filename) - goto out; + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); - VOLGEN_GET_VOLUME_DIR (path, volinfo); + get_brick_filepath (filename, volinfo, brickinfo); - snprintf (filename, PATH_MAX, "%s/%s-fuse.vol", - path, volinfo->volname); + ret = build_server_graph (&graph, volinfo, NULL, brickinfo); + if (!ret) + ret = volgen_write_volfile (&graph, filename); + + volgen_graph_free (&graph); - ret = filename; -out: return ret; } -static int +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); +} + +int generate_brick_volfiles (glusterd_volinfo_t *volinfo) { - glusterd_brickinfo_t *brickinfo = NULL; - char *filename = NULL; - int ret = -1; + glusterd_brickinfo_t *brickinfo = NULL; + char tstamp_file[PATH_MAX] = {0,}; + int ret = -1; + + ret = glusterd_volinfo_get_boolean (volinfo, VKEY_MARKER_XTIME); + if (ret == -1) + return -1; + + 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_log ("", GF_LOG_DEBUG, "timestamp file exist"); + ret = -2; + } + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, "failed to create %s (%s)", + tstamp_file, strerror (errno)); + return -1; + } + if (ret >= 0) + close (ret); + } else { + ret = unlink (tstamp_file); + if (ret == -1 && errno == ENOENT) + ret = 0; + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, "failed to unlink %s (%s)", + tstamp_file, strerror (errno)); + return -1; + } + } list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { gf_log ("", GF_LOG_DEBUG, "Found a brick - %s:%s", brickinfo->hostname, brickinfo->path); - filename = get_brick_filename (volinfo, brickinfo); - if (!filename) { - gf_log ("", GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; - } - - 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); + ret = glusterd_generate_brick_volfile (volinfo, brickinfo); + if (ret) goto out; - } - if (filename) - GF_FREE (filename); } ret = 0; + out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int -glusterfsd_write_nfs_xlator (int fd, char *subvols, char *volume_ids) +generate_single_transport_client_volfile (glusterd_volinfo_t *volinfo, + char *filepath, dict_t *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 graph = {0,}; + int ret = -1; - if (fd <= 0) - return -1; + ret = build_client_graph (&graph, volinfo, dict); + if (!ret) + ret = volgen_write_volfile (&graph, filepath); - dup_subvols = gf_strdup (subvols); - if (!dup_subvols) - return -1; - else - free_ptr = dup_subvols; + volgen_graph_free (&graph); - write (fd, nfs_str, strlen(nfs_str)); + return ret; +} - 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); +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; } - str = "option nfs.dynamic-volumes on\n"; - write (fd, str, strlen (str)); +} - /* Write fsids */ - write (fd, volume_ids, strlen (volume_ids)); +int +generate_client_volfiles (glusterd_volinfo_t *volinfo, + glusterd_client_type_t client_type) +{ + char filepath[PATH_MAX] = {0,}; + int ret = -1; + char *types[] = {NULL, NULL, NULL}; + int i = 0; + dict_t *dict = NULL; + gf_transport_type type = GF_TRANSPORT_TCP; + + enumerate_transport_reqs (volinfo->transport_type, types); + dict = dict_new (); + if (!dict) + goto out; + for (i = 0; types[i]; i++) { + memset (filepath, 0, sizeof (filepath)); + ret = dict_set_str (dict, "client-transport-type", types[i]); + if (ret) + goto out; + type = transport_str_to_type (types[i]); - 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); + ret = dict_set_uint32 (dict, "trusted-client", client_type); + if (ret) + goto out; - return 0; + if (client_type == GF_CLIENT_TRUSTED) { + glusterd_get_trusted_client_filepath (filepath, + volinfo, + type); + } else { + glusterd_get_client_filepath (filepath, + volinfo, + type); + } + + ret = generate_single_transport_client_volfile (volinfo, + filepath, + dict); + if (ret) + goto out; + } +out: + if (dict) + dict_unref (dict); + 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; +glusterd_create_rb_volfiles (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + + ret = glusterd_generate_brick_volfile (volinfo, brickinfo); + if (!ret) + ret = generate_client_volfiles (volinfo, GF_CLIENT_TRUSTED); + if (!ret) + ret = glusterd_fetchspec_notify (THIS); + + return ret; +} + +int +glusterd_create_volfiles_and_notify_services (glusterd_volinfo_t *volinfo) +{ + int ret = -1; + 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"); + + ret = generate_brick_volfiles (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Could not generate volfiles for bricks"); goto out; } - nfs_filepath = glusterd_get_nfs_filepath (volinfo); - if (!nfs_filepath) + ret = generate_client_volfiles (volinfo, GF_CLIENT_TRUSTED); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Could not generate trusted client volfiles"); goto out; + } - 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); + ret = generate_client_volfiles (volinfo, GF_CLIENT_OTHER); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Could not generate client volfiles"); goto out; } + ret = glusterd_fetchspec_notify (this); - 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; +int +glusterd_create_global_volfile (int (*builder) (volgen_graph_t *graph, + dict_t *set_dict), + char *filepath, dict_t *mod_dict) +{ + volgen_graph_t graph = {0,}; + int ret = -1; + + ret = builder (&graph, mod_dict); + if (!ret) + ret = volgen_write_volfile (&graph, filepath); + + volgen_graph_free (&graph); + + return ret; +} + +int +glusterd_create_nfs_volfile () +{ + char filepath[PATH_MAX] = {0,}; + glusterd_conf_t *conf = THIS->private; + + glusterd_get_nodesvc_volfile ("nfs", conf->workdir, + filepath, sizeof (filepath)); + return glusterd_create_global_volfile (build_nfs_graph, + filepath, NULL); +} + +int +glusterd_create_shd_volfile () +{ + char filepath[PATH_MAX] = {0,}; + int ret = -1; + glusterd_conf_t *conf = THIS->private; + dict_t *mod_dict = NULL; + + mod_dict = dict_new (); + if (!mod_dict) + goto out; + + ret = dict_set_uint32 (mod_dict, "cluster.background-self-heal-count", 0); + if (ret) + goto out; + + ret = dict_set_str (mod_dict, "cluster.data-self-heal", "on"); + if (ret) + goto out; + + ret = dict_set_str (mod_dict, "cluster.metadata-self-heal", "on"); + if (ret) + goto out; + + ret = dict_set_str (mod_dict, "cluster.entry-self-heal", "on"); + if (ret) + goto out; + + glusterd_get_nodesvc_volfile ("glustershd", conf->workdir, + filepath, sizeof (filepath)); + ret = glusterd_create_global_volfile (build_shd_graph, filepath, + mod_dict); +out: + if (mod_dict) + dict_unref (mod_dict); + return ret; +} + +int +glusterd_check_nfs_topology_identical (gf_boolean_t *identical) +{ + char nfsvol[PATH_MAX] = {0,}; + char tmpnfsvol[PATH_MAX] = {0,}; + glusterd_conf_t *conf = NULL; + xlator_t *this = THIS; + int ret = -1; + int tmpclean = 0; + int tmpfd = -1; + + if ((!identical) || (!this) || (!this->private)) + goto out; + + conf = (glusterd_conf_t *) this->private; + + /* Fetch the original NFS volfile */ + glusterd_get_nodesvc_volfile ("nfs", conf->workdir, + nfsvol, sizeof (nfsvol)); + + /* Create the temporary NFS volfile */ + snprintf (tmpnfsvol, sizeof (tmpnfsvol), "/tmp/gnfs-XXXXXX"); + tmpfd = mkstemp (tmpnfsvol); + if (tmpfd < 0) { + gf_log (this->name, GF_LOG_WARNING, + "Unable to create temp file %s: (%s)", + tmpnfsvol, strerror (errno)); 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; + + tmpclean = 1; /* SET the flag to unlink() tmpfile */ + + ret = glusterd_create_global_volfile (build_nfs_graph, + tmpnfsvol, NULL); + if (ret) + goto out; + + /* Compare the topology of volfiles */ + ret = glusterd_check_topology_identical (nfsvol, tmpnfsvol, + identical); +out: + if (tmpfd >= 0) + close (tmpfd); + if (tmpclean) + unlink (tmpnfsvol); + return ret; +} + +int +glusterd_check_nfs_volfile_identical (gf_boolean_t *identical) +{ + char nfsvol[PATH_MAX] = {0,}; + char tmpnfsvol[PATH_MAX] = {0,}; + glusterd_conf_t *conf = NULL; + xlator_t *this = NULL; + int ret = -1; + int need_unlink = 0; + int tmp_fd = -1; + + this = THIS; + + GF_ASSERT (this); + GF_ASSERT (identical); + + conf = this->private; + + glusterd_get_nodesvc_volfile ("nfs", conf->workdir, + nfsvol, sizeof (nfsvol)); + + snprintf (tmpnfsvol, sizeof (tmpnfsvol), "/tmp/gnfs-XXXXXX"); + + tmp_fd = mkstemp (tmpnfsvol); + if (tmp_fd < 0) { + gf_log ("", GF_LOG_WARNING, "Unable to create temp file %s: " + "(%s)", tmpnfsvol, strerror (errno)); goto out; } - 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; + need_unlink = 1; + + ret = glusterd_create_global_volfile (build_nfs_graph, + tmpnfsvol, NULL); + if (ret) + goto out; + + ret = glusterd_check_files_identical (nfsvol, tmpnfsvol, + identical); + if (ret) + goto out; + +out: + if (need_unlink) + unlink (tmpnfsvol); + + if (tmp_fd >= 0) + close (tmp_fd); + + return ret; +} + +int +glusterd_delete_volfile (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = 0; + char filename[PATH_MAX] = {0,}; + + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + + get_brick_filepath (filename, volinfo, brickinfo); + ret = unlink (filename); + if (ret) + gf_log ("glusterd", GF_LOG_ERROR, "failed to delete file: %s, " + "reason: %s", filename, strerror (errno)); + return ret; +} + +int +validate_shdopts (glusterd_volinfo_t *volinfo, + dict_t *val_dict, + char **op_errstr) +{ + volgen_graph_t graph = {0,}; + int ret = -1; + + graph.errstr = op_errstr; + + if (!glusterd_is_volume_replicate (volinfo)) { + ret = 0; goto out; } + ret = dict_set_str (val_dict, "graph-check", "on"); + if (ret) + goto out; + ret = build_shd_graph (&graph, val_dict); + if (!ret) + ret = graph_reconf_validateopt (&graph.graph, op_errstr); - voliter = NULL; - list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (voliter->status != GLUSTERD_STATUS_STARTED) - continue; + volgen_graph_free (&graph); - gf_log ("", GF_LOG_DEBUG, - "adding fuse info of - %s", voliter->volname); + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); +out: + dict_del (val_dict, "graph-check"); + return ret; +} - snprintf (fuse_subvols, sizeof(fuse_subvols), " %s", voliter->volname); - fuse_filepath = get_client_filepath (voliter); - if (!fuse_filepath) { - ret = -1; - goto out; - } +int +validate_nfsopts (glusterd_volinfo_t *volinfo, + dict_t *val_dict, + char **op_errstr) +{ + volgen_graph_t graph = {0,}; + int ret = -1; + char transport_type[16] = {0,}; + char *tt = NULL; + char err_str[4096] = {0,}; + xlator_t *this = THIS; + + GF_ASSERT (this); - fuse_fd = open (fuse_filepath, O_RDONLY); - if (fuse_fd < 0) { - gf_log ("", GF_LOG_ERROR, "Could not open file: %s", - fuse_filepath); + graph.errstr = op_errstr; + + get_vol_transport_type (volinfo, transport_type); + ret = dict_get_str (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_log (this->name, GF_LOG_ERROR, "%s", err_str); + *op_errstr = gf_strdup (err_str); ret = -1; goto out; } - - 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 { + if (strcmp (tt,"tcp") && strcmp (tt,"rdma")) { + snprintf (err_str, sizeof (err_str), "wrong transport " + "type %s", tt); + *op_errstr = gf_strdup (err_str); 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 = glusterfsd_write_nfs_xlator (nfs_fd, nfs_subvols, nfs_vol_id); - if (ret) + ret = dict_set_str (val_dict, "volume-name", volinfo->volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set volume name"); goto out; + } - 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; + ret = build_nfs_graph (&graph, val_dict); + if (!ret) + ret = graph_reconf_validateopt (&graph.graph, op_errstr); + + volgen_graph_free (&graph); + +out: + if (dict_get (val_dict, "volume-name")) + dict_del (val_dict, "volume-name"); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + + +int +validate_clientopts (glusterd_volinfo_t *volinfo, + dict_t *val_dict, + char **op_errstr) +{ + volgen_graph_t graph = {0,}; + int ret = -1; + + 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_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +validate_brickopts (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + dict_t *val_dict, + char **op_errstr) +{ + volgen_graph_t graph = {0,}; + int ret = -1; + + GF_ASSERT (volinfo); + + graph.errstr = op_errstr; + + ret = build_server_graph (&graph, volinfo, val_dict, brickinfo); + if (!ret) + ret = graph_reconf_validateopt (&graph.graph, op_errstr); + + volgen_graph_free (&graph); + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +glusterd_validate_brickreconf (glusterd_volinfo_t *volinfo, + dict_t *val_dict, + char **op_errstr) +{ + glusterd_brickinfo_t *brickinfo = NULL; + int ret = -1; + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + gf_log ("", GF_LOG_DEBUG, + "Validating %s", brickinfo->hostname); + + ret = validate_brickopts (volinfo, brickinfo, val_dict, + op_errstr); + if (ret) + goto out; } - *pad = '\0'; - ret = rename (nfs_filepath, nfs_orig_path); + + ret = 0; + 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; } static int -generate_client_volfiles (glusterd_volinfo_t *volinfo) +_check_globalopt (dict_t *this, char *key, data_t *value, void *ret_val) { - char *filename = NULL; - int ret = -1; + int *ret = NULL; - filename = get_client_filepath (volinfo); - if (!filename) { - gf_log ("", GF_LOG_ERROR, - "Out of memory"); - ret = -1; + ret = ret_val; + if (*ret) + return 0; + if (!glusterd_check_globaloption (key)) + *ret = 1; + + return 0; +} + +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_log ("", GF_LOG_DEBUG, + "Could not Validate bricks"); goto out; } - ret = generate_client_volfile (volinfo, filename); + ret = validate_clientopts (volinfo, val_dict, op_errstr); if (ret) { gf_log ("", GF_LOG_DEBUG, - "Could not generate volfile for client"); + "Could not Validate client"); goto out; } -out: - if (filename) - GF_FREE (filename); + ret = validate_nfsopts (volinfo, val_dict, op_errstr); + if (ret) { + gf_log ("", GF_LOG_DEBUG, "Could not Validate nfs"); + goto out; + } + ret = validate_shdopts (volinfo, val_dict, op_errstr); + if (ret) { + gf_log ("", GF_LOG_DEBUG, "Could not Validate self-heald"); + goto out; + } + +out: + gf_log ("", GF_LOG_DEBUG, "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_create_volfiles (glusterd_volinfo_t *volinfo) +glusterd_validate_reconfopts (glusterd_volinfo_t *volinfo, dict_t *val_dict, + char **op_errstr) { - int ret = -1; + int ret = 0; - 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"); + dict_foreach (val_dict, _check_localopt, &ret); + if (ret) { + *op_errstr = gf_strdup ( "option specified is not a local option"); + return -1; } - ret = generate_brick_volfiles (volinfo); + ret = glusterd_validate_brickreconf (volinfo, val_dict, op_errstr); + if (ret) { gf_log ("", GF_LOG_DEBUG, - "Could not generate volfiles for bricks"); + "Could not Validate bricks"); goto out; } - ret = generate_client_volfiles (volinfo); + ret = validate_clientopts (volinfo, val_dict, op_errstr); if (ret) { gf_log ("", GF_LOG_DEBUG, - "Could not generate volfile for client"); + "Could not Validate client"); + goto out; + } + + ret = validate_nfsopts (volinfo, val_dict, op_errstr); + if (ret) { + gf_log ("", GF_LOG_DEBUG, "Could not Validate nfs"); + goto out; + } + + + ret = validate_shdopts (volinfo, val_dict, op_errstr); + if (ret) { + gf_log ("", GF_LOG_DEBUG, "Could not Validate self-heald"); goto out; } - ret = glusterd_fetchspec_notify (THIS); out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } +static struct volopt_map_entry * +_gd_get_vmep (char *key) { + char *completion = NULL; + struct volopt_map_entry *vmep = NULL; + int ret = 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; +} + +uint32_t +glusterd_get_op_version_for_key (char *key) +{ + struct volopt_map_entry *vmep = NULL; + + GF_ASSERT (key); + + vmep = _gd_get_vmep (key); + if (vmep) + return vmep->op_version; + + return 0; +} + +gf_boolean_t +gd_is_client_option (char *key) +{ + struct volopt_map_entry *vmep = NULL; + + GF_ASSERT (key); + + vmep = _gd_get_vmep (key); + if (vmep && (vmep->flags & OPT_FLAG_CLIENT_OPT)) + return _gf_true; + + return _gf_false; +} + +gf_boolean_t +gd_is_xlator_option (char *key) +{ + struct volopt_map_entry *vmep = NULL; + + GF_ASSERT (key); + + vmep = _gd_get_vmep (key); + if (vmep && (vmep->flags & OPT_FLAG_XLATOR_OPT)) + return _gf_true; + + return _gf_false; +} + +volume_option_type_t +_gd_get_option_type (char *key) +{ + struct volopt_map_entry *vmep = NULL; + 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; + + GF_ASSERT (key); + + vmep = _gd_get_vmep (key); + + if (vmep) { + 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 (dl_handle) { + dlclose (dl_handle); + dl_handle = NULL; + } + + return opt_type; +} + +gf_boolean_t +gd_is_boolean_option (char *key) +{ + GF_ASSERT (key); + + if (GF_OPTION_TYPE_BOOL == _gd_get_option_type (key)) + return _gf_true; + + return _gf_false; +} + +/* This function will restore origin volume to it's snap. + * The restore operation will simply replace the Gluster origin + * volume with the snap volume. + * TODO: Multi-volume delete to be done. + * Cleanup in case of restore failure is pending. + * + * @param orig_vol volinfo of origin volume + * @param snap_vol volinfo of snapshot volume + * + * @return 0 on success and negative value on error + */ int -glusterd_delete_volfile (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +gd_restore_snap_volume (dict_t *rsp_dict, + glusterd_volinfo_t *orig_vol, + glusterd_volinfo_t *snap_vol) { - char *filename = NULL; + int ret = -1; + glusterd_volinfo_t *new_volinfo = NULL; + glusterd_snap_t *snap = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + glusterd_volinfo_t *temp_volinfo = NULL; + glusterd_volinfo_t *voliter = NULL; - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); + this = THIS; + GF_ASSERT (this); + GF_ASSERT (rsp_dict); + conf = this->private; + GF_ASSERT (conf); + + GF_VALIDATE_OR_GOTO (this->name, orig_vol, out); + GF_VALIDATE_OR_GOTO (this->name, snap_vol, out); + snap = snap_vol->snapshot; + GF_VALIDATE_OR_GOTO (this->name, snap, out); + + /* Snap volume must be stoped before performing the + * restore operation. + */ + ret = glusterd_stop_volume (snap_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to stop " + "snap volume"); + goto out; + } + + /* Create a new volinfo for the restored volume */ + ret = glusterd_volinfo_dup (snap_vol, &new_volinfo, _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to create volinfo"); + goto out; + } - filename = get_brick_filename (volinfo, brickinfo); + /* Following entries need to be derived from origin volume. */ + strcpy (new_volinfo->volname, orig_vol->volname); + uuid_copy (new_volinfo->volume_id, orig_vol->volume_id); + new_volinfo->snap_count = orig_vol->snap_count; + new_volinfo->snap_max_hard_limit = orig_vol->snap_max_hard_limit; + new_volinfo->is_volume_restored = _gf_true; - if (filename) - unlink (filename); + /* Bump the version of the restored volume, so that nodes * + * which are done can sync during handshake */ + new_volinfo->version = orig_vol->version; - if (filename) - GF_FREE (filename); - return 0; + list_for_each_entry_safe (voliter, temp_volinfo, + &orig_vol->snap_volumes, snapvol_list) { + list_add_tail (&voliter->snapvol_list, + &new_volinfo->snap_volumes); + } + /* Copy the snap vol info to the new_volinfo.*/ + ret = glusterd_snap_volinfo_restore (rsp_dict, new_volinfo, snap_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to restore snap"); + (void)glusterd_volinfo_delete (new_volinfo); + goto out; + } + + /* If the orig_vol is already restored then we should delete + * the backend LVMs */ + if (orig_vol->is_volume_restored) { + ret = glusterd_lvm_snapshot_remove (rsp_dict, orig_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to remove " + "LVM backend"); + (void)glusterd_volinfo_delete (new_volinfo); + goto out; + } + } + + /* Once the new_volinfo is completely constructed then delete + * the orinal volinfo + */ + ret = glusterd_volinfo_delete (orig_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to delete volinfo"); + (void)glusterd_volinfo_delete (new_volinfo); + goto out; + } + + /* New volinfo always shows the status as created. Therefore + * set the status to stop. */ + glusterd_set_volume_status (new_volinfo, GLUSTERD_STATUS_STOPPED); + + list_add_tail (&new_volinfo->vol_list, &conf->volumes); + + /* Now delete the snap entry. As a first step delete the snap + * volume information stored in store. */ + ret = glusterd_snap_remove (rsp_dict, snap, _gf_false, _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Failed to delete " + "snap %s", snap->snapname); + goto out; + } + + ret = glusterd_store_volinfo (new_volinfo, + GLUSTERD_VOLINFO_VER_AC_INCREMENT); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to store volinfo"); + goto out; + } + + ret = 0; +out: + + return ret; } |
