summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'libglusterfs/src/graph.c')
-rw-r--r--libglusterfs/src/graph.c751
1 files changed, 751 insertions, 0 deletions
diff --git a/libglusterfs/src/graph.c b/libglusterfs/src/graph.c
new file mode 100644
index 000000000..e76df1ca5
--- /dev/null
+++ b/libglusterfs/src/graph.c
@@ -0,0 +1,751 @@
+/*
+ Copyright (c) 2008-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 "xlator.h"
+#include <dlfcn.h>
+#include <netdb.h>
+#include <fnmatch.h>
+#include "defaults.h"
+
+
+#if 0
+static void
+_gf_dump_details (int argc, char **argv)
+{
+ extern FILE *gf_log_logfile;
+ int i = 0;
+ char timestr[64];
+ time_t utime = 0;
+ pid_t mypid = 0;
+ struct utsname uname_buf = {{0, }, };
+ int uname_ret = -1;
+
+ mypid = getpid ();
+ uname_ret = uname (&uname_buf);
+
+ utime = time (NULL);
+ gf_time_fmt (timestr, sizeof timestr, utime, gf_timefmt_FT);
+ fprintf (gf_log_logfile,
+ "========================================"
+ "========================================\n");
+ fprintf (gf_log_logfile, "Version : %s %s built on %s %s\n",
+ PACKAGE_NAME, PACKAGE_VERSION, __DATE__, __TIME__);
+ fprintf (gf_log_logfile, "git: %s\n",
+ GLUSTERFS_REPOSITORY_REVISION);
+ fprintf (gf_log_logfile, "Starting Time: %s\n", timestr);
+ fprintf (gf_log_logfile, "Command line : ");
+ for (i = 0; i < argc; i++) {
+ fprintf (gf_log_logfile, "%s ", argv[i]);
+ }
+
+ fprintf (gf_log_logfile, "\nPID : %d\n", mypid);
+
+ if (uname_ret == 0) {
+ fprintf (gf_log_logfile, "System name : %s\n",
+ uname_buf.sysname);
+ fprintf (gf_log_logfile, "Nodename : %s\n",
+ uname_buf.nodename);
+ fprintf (gf_log_logfile, "Kernel Release : %s\n",
+ uname_buf.release);
+ fprintf (gf_log_logfile, "Hardware Identifier: %s\n",
+ uname_buf.machine);
+ }
+
+
+ fprintf (gf_log_logfile, "\n");
+ fflush (gf_log_logfile);
+}
+#endif
+
+
+
+int
+glusterfs_xlator_link (xlator_t *pxl, xlator_t *cxl)
+{
+ xlator_list_t *xlchild = NULL;
+ xlator_list_t *xlparent = NULL;
+ xlator_list_t **tmp = NULL;
+
+ xlparent = (void *) GF_CALLOC (1, sizeof (*xlparent),
+ gf_common_mt_xlator_list_t);
+ if (!xlparent)
+ return -1;
+
+ xlchild = (void *) GF_CALLOC (1, sizeof (*xlchild),
+ gf_common_mt_xlator_list_t);
+ if (!xlchild) {
+ GF_FREE (xlparent);
+
+ return -1;
+ }
+
+ xlparent->xlator = pxl;
+ for (tmp = &cxl->parents; *tmp; tmp = &(*tmp)->next);
+ *tmp = xlparent;
+
+ xlchild->xlator = cxl;
+ for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next);
+ *tmp = xlchild;
+
+ return 0;
+}
+
+
+void
+glusterfs_graph_set_first (glusterfs_graph_t *graph, xlator_t *xl)
+{
+ xl->next = graph->first;
+ if (graph->first)
+ ((xlator_t *)graph->first)->prev = xl;
+ graph->first = xl;
+
+ graph->xl_count++;
+}
+
+
+int
+glusterfs_graph_insert (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx,
+ const char *type, const char *name,
+ gf_boolean_t autoload)
+{
+ xlator_t *ixl = NULL;
+
+ if (!ctx->master) {
+ gf_log ("glusterfs", GF_LOG_ERROR,
+ "volume \"%s\" can be added from command line only "
+ "on client side", type);
+
+ return -1;
+ }
+
+ ixl = GF_CALLOC (1, sizeof (*ixl), gf_common_mt_xlator_t);
+ if (!ixl)
+ return -1;
+
+ ixl->ctx = ctx;
+ ixl->graph = graph;
+ ixl->options = get_new_dict ();
+ if (!ixl->options)
+ goto err;
+
+ ixl->name = gf_strdup (name);
+ if (!ixl->name)
+ goto err;
+
+ ixl->is_autoloaded = autoload;
+
+ if (xlator_set_type (ixl, type) == -1) {
+ gf_log ("glusterfs", GF_LOG_ERROR,
+ "%s (%s) initialization failed",
+ name, type);
+ return -1;
+ }
+
+ if (glusterfs_xlator_link (ixl, graph->top) == -1)
+ goto err;
+ glusterfs_graph_set_first (graph, ixl);
+ graph->top = ixl;
+
+ return 0;
+err:
+ xlator_destroy (ixl);
+ return -1;
+}
+
+int
+glusterfs_graph_acl (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ int ret = 0;
+ cmd_args_t *cmd_args = NULL;
+
+ cmd_args = &ctx->cmd_args;
+
+ if (!cmd_args->acl)
+ return 0;
+
+ ret = glusterfs_graph_insert (graph, ctx, "system/posix-acl",
+ "posix-acl-autoload", 1);
+ return ret;
+}
+
+int
+glusterfs_graph_worm (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ int ret = 0;
+ cmd_args_t *cmd_args = NULL;
+
+ cmd_args = &ctx->cmd_args;
+
+ if (!cmd_args->worm)
+ return 0;
+
+ ret = glusterfs_graph_insert (graph, ctx, "features/worm",
+ "worm-autoload", 1);
+ return ret;
+}
+
+int
+glusterfs_graph_mac_compat (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ int ret = 0;
+ cmd_args_t *cmd_args = NULL;
+
+ cmd_args = &ctx->cmd_args;
+
+ if (cmd_args->mac_compat == GF_OPTION_DISABLE)
+ return 0;
+
+ ret = glusterfs_graph_insert (graph, ctx, "features/mac-compat",
+ "mac-compat-autoload", 1);
+
+ return ret;
+}
+
+int
+glusterfs_graph_gfid_access (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ int ret = 0;
+ cmd_args_t *cmd_args = NULL;
+
+ cmd_args = &ctx->cmd_args;
+
+ if (!cmd_args->aux_gfid_mount)
+ return 0;
+
+ ret = glusterfs_graph_insert (graph, ctx, "features/gfid-access",
+ "gfid-access-autoload", 1);
+ return ret;
+}
+
+static void
+gf_add_cmdline_options (glusterfs_graph_t *graph, cmd_args_t *cmd_args)
+{
+ int ret = 0;
+ xlator_t *trav = NULL;
+ xlator_cmdline_option_t *cmd_option = NULL;
+
+ trav = graph->first;
+
+ while (trav) {
+ list_for_each_entry (cmd_option,
+ &cmd_args->xlator_options, cmd_args) {
+ if (!fnmatch (cmd_option->volume,
+ trav->name, FNM_NOESCAPE)) {
+ ret = dict_set_str (trav->options,
+ cmd_option->key,
+ cmd_option->value);
+ if (ret == 0) {
+ gf_log (trav->name, GF_LOG_INFO,
+ "adding option '%s' for "
+ "volume '%s' with value '%s'",
+ cmd_option->key, trav->name,
+ cmd_option->value);
+ } else {
+ gf_log (trav->name, GF_LOG_WARNING,
+ "adding option '%s' for "
+ "volume '%s' failed: %s",
+ cmd_option->key, trav->name,
+ strerror (-ret));
+ }
+ }
+ }
+ trav = trav->next;
+ }
+}
+
+
+int
+glusterfs_graph_validate_options (glusterfs_graph_t *graph)
+{
+ xlator_t *trav = NULL;
+ int ret = -1;
+ char *errstr = NULL;
+
+ trav = graph->first;
+
+ while (trav) {
+ if (list_empty (&trav->volume_options))
+ continue;
+
+ ret = xlator_options_validate (trav, trav->options, &errstr);
+ if (ret) {
+ gf_log (trav->name, GF_LOG_ERROR,
+ "validation failed: %s", errstr);
+ return ret;
+ }
+ trav = trav->next;
+ }
+
+ return 0;
+}
+
+
+int
+glusterfs_graph_init (glusterfs_graph_t *graph)
+{
+ xlator_t *trav = NULL;
+ int ret = -1;
+
+ trav = graph->first;
+
+ while (trav) {
+ ret = xlator_init (trav);
+ if (ret) {
+ gf_log (trav->name, GF_LOG_ERROR,
+ "initializing translator failed");
+ return ret;
+ }
+ trav = trav->next;
+ }
+
+ return 0;
+}
+
+
+static int
+_log_if_unknown_option (dict_t *dict, char *key, data_t *value, void *data)
+{
+ volume_option_t *found = NULL;
+ xlator_t *xl = NULL;
+
+ xl = data;
+
+ found = xlator_volume_option_get (xl, key);
+
+ if (!found) {
+ gf_log (xl->name, GF_LOG_WARNING,
+ "option '%s' is not recognized", key);
+ }
+
+ return 0;
+}
+
+
+static void
+_xlator_check_unknown_options (xlator_t *xl, void *data)
+{
+ dict_foreach (xl->options, _log_if_unknown_option, xl);
+}
+
+
+int
+glusterfs_graph_unknown_options (glusterfs_graph_t *graph)
+{
+ xlator_foreach (graph->first, _xlator_check_unknown_options, NULL);
+ return 0;
+}
+
+
+void
+fill_uuid (char *uuid, int size)
+{
+ char hostname[256] = {0,};
+ struct timeval tv = {0,};
+ char now_str[64];
+
+ if (gettimeofday (&tv, NULL) == -1) {
+ gf_log ("graph", GF_LOG_ERROR,
+ "gettimeofday: failed %s",
+ strerror (errno));
+ }
+
+ if (gethostname (hostname, 256) == -1) {
+ gf_log ("graph", GF_LOG_ERROR,
+ "gethostname: failed %s",
+ strerror (errno));
+ }
+
+ gf_time_fmt (now_str, sizeof now_str, tv.tv_sec, gf_timefmt_Ymd_T);
+ snprintf (uuid, size, "%s-%d-%s:%"GF_PRI_SUSECONDS,
+ hostname, getpid(), now_str, tv.tv_usec);
+
+ return;
+}
+
+
+int
+glusterfs_graph_settop (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ const char *volume_name = NULL;
+ xlator_t *trav = NULL;
+
+ volume_name = ctx->cmd_args.volume_name;
+
+ if (!volume_name) {
+ graph->top = graph->first;
+ return 0;
+ }
+
+ for (trav = graph->first; trav; trav = trav->next) {
+ if (strcmp (trav->name, volume_name) == 0) {
+ graph->top = trav;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int
+glusterfs_graph_parent_up (glusterfs_graph_t *graph)
+{
+ xlator_t *trav = NULL;
+ int ret = -1;
+
+ trav = graph->first;
+
+ while (trav) {
+ if (!xlator_has_parent (trav)) {
+ ret = xlator_notify (trav, GF_EVENT_PARENT_UP, trav);
+ }
+
+ if (ret)
+ break;
+
+ trav = trav->next;
+ }
+
+ return ret;
+}
+
+
+int
+glusterfs_graph_prepare (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ xlator_t *trav = NULL;
+ int ret = 0;
+
+ /* XXX: CHECKSUM */
+
+ /* XXX: attach to -n volname */
+ ret = glusterfs_graph_settop (graph, ctx);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "glusterfs graph settop failed");
+ return -1;
+ }
+
+ /* XXX: WORM VOLUME */
+ ret = glusterfs_graph_worm (graph, ctx);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "glusterfs graph worm failed");
+ return -1;
+ }
+ ret = glusterfs_graph_acl (graph, ctx);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "glusterfs graph ACL failed");
+ return -1;
+ }
+
+ /* XXX: MAC COMPAT */
+ ret = glusterfs_graph_mac_compat (graph, ctx);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "glusterfs graph mac compat failed");
+ return -1;
+ }
+
+ /* XXX: gfid-access */
+ ret = glusterfs_graph_gfid_access (graph, ctx);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR,
+ "glusterfs graph 'gfid-access' failed");
+ return -1;
+ }
+
+ /* XXX: this->ctx setting */
+ for (trav = graph->first; trav; trav = trav->next) {
+ trav->ctx = ctx;
+ }
+
+ /* XXX: DOB setting */
+ gettimeofday (&graph->dob, NULL);
+
+ fill_uuid (graph->graph_uuid, 128);
+
+ graph->id = ctx->graph_id++;
+
+ /* XXX: --xlator-option additions */
+ gf_add_cmdline_options (graph, &ctx->cmd_args);
+
+
+ return 0;
+}
+
+
+int
+glusterfs_graph_activate (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
+{
+ int ret = 0;
+
+ /* XXX: all xlator options validation */
+ ret = glusterfs_graph_validate_options (graph);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "validate options failed");
+ return ret;
+ }
+
+ /* XXX: perform init () */
+ ret = glusterfs_graph_init (graph);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "init failed");
+ return ret;
+ }
+
+ ret = glusterfs_graph_unknown_options (graph);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "unknown options failed");
+ return ret;
+ }
+
+ /* XXX: log full graph (_gf_dump_details) */
+
+ list_add (&graph->list, &ctx->graphs);
+ ctx->active = graph;
+
+ /* XXX: attach to master and set active pointer */
+ if (ctx->master) {
+ ret = xlator_notify (ctx->master, GF_EVENT_GRAPH_NEW, graph);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR,
+ "graph new notification failed");
+ return ret;
+ }
+ ((xlator_t *)ctx->master)->next = graph->top;
+ }
+
+ /* XXX: perform parent up */
+ ret = glusterfs_graph_parent_up (graph);
+ if (ret) {
+ gf_log ("graph", GF_LOG_ERROR, "parent up notification failed");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int
+xlator_equal_rec (xlator_t *xl1, xlator_t *xl2)
+{
+ xlator_list_t *trav1 = NULL;
+ xlator_list_t *trav2 = NULL;
+ int ret = 0;
+
+ if (xl1 == NULL || xl2 == NULL) {
+ gf_log ("xlator", GF_LOG_DEBUG, "invalid argument");
+ return -1;
+ }
+
+ trav1 = xl1->children;
+ trav2 = xl2->children;
+
+ while (trav1 && trav2) {
+ ret = xlator_equal_rec (trav1->xlator, trav2->xlator);
+ if (ret) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "xlators children not equal");
+ goto out;
+ }
+
+ trav1 = trav1->next;
+ trav2 = trav2->next;
+ }
+
+ if (trav1 || trav2) {
+ ret = -1;
+ goto out;
+ }
+
+ if (strcmp (xl1->name, xl2->name)) {
+ ret = -1;
+ goto out;
+ }
+
+ /* type could have changed even if xlator names match,
+ e.g cluster/distrubte and cluster/nufa share the same
+ xlator name
+ */
+ if (strcmp (xl1->type, xl2->type)) {
+ ret = -1;
+ goto out;
+ }
+out :
+ return ret;
+}
+
+
+gf_boolean_t
+is_graph_topology_equal (glusterfs_graph_t *graph1, glusterfs_graph_t *graph2)
+{
+ xlator_t *trav1 = NULL;
+ xlator_t *trav2 = NULL;
+ gf_boolean_t ret = _gf_true;
+
+ trav1 = graph1->first;
+ trav2 = graph2->first;
+
+ ret = xlator_equal_rec (trav1, trav2);
+
+ if (ret) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "graphs are not equal");
+ ret = _gf_false;
+ goto out;
+ }
+
+ ret = _gf_true;
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "graphs are equal");
+
+out:
+ return ret;
+}
+
+
+/* Function has 3types of return value 0, -ve , 1
+ * return 0 =======> reconfiguration of options has succeeded
+ * return 1 =======> the graph has to be reconstructed and all the xlators should be inited
+ * return -1(or -ve) =======> Some Internal Error occurred during the operation
+ */
+int
+glusterfs_volfile_reconfigure (int oldvollen, FILE *newvolfile_fp,
+ glusterfs_ctx_t *ctx, const char *oldvolfile)
+{
+ glusterfs_graph_t *oldvolfile_graph = NULL;
+ glusterfs_graph_t *newvolfile_graph = NULL;
+ FILE *oldvolfile_fp = NULL;
+ gf_boolean_t active_graph_found = _gf_true;
+
+ int ret = -1;
+
+ if (!oldvollen) {
+ ret = 1; // Has to call INIT for the whole graph
+ goto out;
+ }
+
+ if (!ctx) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
+ "ctx is NULL");
+ goto out;
+ }
+
+ oldvolfile_graph = ctx->active;
+ if (!oldvolfile_graph) {
+ active_graph_found = _gf_false;
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
+ "glusterfs_ctx->active is NULL");
+
+ oldvolfile_fp = tmpfile ();
+ if (!oldvolfile_fp) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR, "Unable to "
+ "create temporary volfile: (%s)",
+ strerror (errno));
+ goto out;
+ }
+
+ fwrite (oldvolfile, oldvollen, 1, oldvolfile_fp);
+ fflush (oldvolfile_fp);
+ if (ferror (oldvolfile_fp)) {
+ goto out;
+ }
+
+ oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp);
+ if (!oldvolfile_graph)
+ goto out;
+ }
+
+ newvolfile_graph = glusterfs_graph_construct (newvolfile_fp);
+ if (!newvolfile_graph) {
+ goto out;
+ }
+
+ if (!is_graph_topology_equal (oldvolfile_graph,
+ newvolfile_graph)) {
+
+ ret = 1;
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "Graph topology not equal(should call INIT)");
+ goto out;
+ }
+
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "Only options have changed in the new "
+ "graph");
+
+ /* */
+ ret = glusterfs_graph_reconfigure (oldvolfile_graph,
+ newvolfile_graph);
+ if (ret) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "Could not reconfigure new options in old graph");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (oldvolfile_fp)
+ fclose (oldvolfile_fp);
+
+ /* Do not simply destroy the old graph here. If the oldgraph
+ is constructed here in this function itself instead of getting
+ it from ctx->active (which happens only of ctx->active is NULL),
+ then destroy the old graph. If some i/o is still happening in
+ the old graph and the old graph is obtained from ctx->active,
+ then destroying the graph will cause problems.
+ */
+ if (!active_graph_found && oldvolfile_graph)
+ glusterfs_graph_destroy (oldvolfile_graph);
+ if (newvolfile_graph)
+ glusterfs_graph_destroy (newvolfile_graph);
+
+ return ret;
+}
+
+
+int
+glusterfs_graph_reconfigure (glusterfs_graph_t *oldgraph,
+ glusterfs_graph_t *newgraph)
+{
+ xlator_t *old_xl = NULL;
+ xlator_t *new_xl = NULL;
+
+ GF_ASSERT (oldgraph);
+ GF_ASSERT (newgraph);
+
+ old_xl = oldgraph->first;
+ while (old_xl->is_autoloaded) {
+ old_xl = old_xl->children->xlator;
+ }
+
+ new_xl = newgraph->first;
+ while (new_xl->is_autoloaded) {
+ new_xl = new_xl->children->xlator;
+ }
+
+ return xlator_tree_reconfigure (old_xl, new_xl);
+}
+
+int
+glusterfs_graph_destroy (glusterfs_graph_t *graph)
+{
+ xlator_tree_free (graph->first);
+
+ if (graph) {
+ list_del_init (&graph->list);
+ GF_FREE (graph);
+ }
+
+ return 0;
+}