"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/libglusterfs/src/graph.c" (16 Sep 2020, 51813 Bytes) of package /linux/misc/glusterfs-8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "graph.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
    3   This file is part of GlusterFS.
    4 
    5   This file is licensed to you under your choice of the GNU Lesser
    6   General Public License, version 3 or any later version (LGPLv3 or
    7   later), or the GNU General Public License, version 2 (GPLv2), in all
    8   cases as published by the Free Software Foundation.
    9 */
   10 
   11 #include <stdint.h>                  // for uint32_t
   12 #include <sys/time.h>                // for timeval
   13 #include <errno.h>                   // for EIO, errno, EINVAL, ENOMEM
   14 #include <fnmatch.h>                 // for fnmatch, FNM_NOESCAPE
   15 #include <openssl/sha.h>             // for SHA256_DIGEST_LENGTH
   16 #include <regex.h>                   // for regmatch_t, regcomp
   17 #include <stdio.h>                   // for fclose, fopen, snprintf
   18 #include <stdlib.h>                  // for NULL, atoi, mkstemp
   19 #include <string.h>                  // for strcmp, strerror, memcpy
   20 #include <strings.h>                 // for rindex
   21 #include <sys/stat.h>                // for stat
   22 #include <sys/time.h>                // for gettimeofday
   23 #include <unistd.h>                  // for gethostname, getpid
   24 #include "glusterfs/common-utils.h"  // for gf_strncpy, gf_time_fmt
   25 #include "glusterfs/defaults.h"
   26 #include "glusterfs/dict.h"                   // for dict_foreach, dict_set_...
   27 #include "glusterfs/globals.h"                // for xlator_t, xlator_list_t
   28 #include "glusterfs/glusterfs.h"              // for glusterfs_graph_t, glus...
   29 #include "glusterfs/glusterfs-fops.h"         // for GF_EVENT_GRAPH_NEW, GF_...
   30 #include "glusterfs/libglusterfs-messages.h"  // for LG_MSG_GRAPH_ERROR, LG_...
   31 #include "glusterfs/list.h"                   // for list_add, list_del_init
   32 #include "glusterfs/logging.h"                // for gf_msg, GF_LOG_ERROR
   33 #include "glusterfs/mem-pool.h"               // for GF_FREE, gf_strdup, GF_...
   34 #include "glusterfs/mem-types.h"              // for gf_common_mt_xlator_list_t
   35 #include "glusterfs/options.h"                // for xlator_tree_reconfigure
   36 #include "glusterfs/syscall.h"                // for sys_close, sys_stat
   37 
   38 #if 0
   39 static void
   40 _gf_dump_details (int argc, char **argv)
   41 {
   42         extern FILE *gf_log_logfile;
   43         int          i = 0;
   44         char         timestr[64];
   45         time_t       utime = 0;
   46         pid_t        mypid = 0;
   47         struct utsname uname_buf = {{0, }, };
   48         int            uname_ret = -1;
   49 
   50         mypid = getpid ();
   51         uname_ret   = uname (&uname_buf);
   52 
   53         utime = time (NULL);
   54         gf_time_fmt (timestr, sizeof timestr, utime, gf_timefmt_FT);
   55         fprintf (gf_log_logfile,
   56                  "========================================"
   57                  "========================================\n");
   58         fprintf (gf_log_logfile, "Version      : %s %s built on %s %s\n",
   59                  PACKAGE_NAME, PACKAGE_VERSION, __DATE__, __TIME__);
   60         fprintf (gf_log_logfile, "git: %s\n",
   61                  GLUSTERFS_REPOSITORY_REVISION);
   62         fprintf (gf_log_logfile, "Starting Time: %s\n", timestr);
   63         fprintf (gf_log_logfile, "Command line : ");
   64         for (i = 0; i < argc; i++) {
   65                 fprintf (gf_log_logfile, "%s ", argv[i]);
   66         }
   67 
   68         fprintf (gf_log_logfile, "\nPID          : %d\n", mypid);
   69 
   70         if (uname_ret == 0) {
   71                 fprintf (gf_log_logfile, "System name  : %s\n",
   72                          uname_buf.sysname);
   73                 fprintf (gf_log_logfile, "Nodename     : %s\n",
   74                          uname_buf.nodename);
   75                 fprintf (gf_log_logfile, "Kernel Release : %s\n",
   76                          uname_buf.release);
   77                 fprintf (gf_log_logfile, "Hardware Identifier: %s\n",
   78                          uname_buf.machine);
   79         }
   80 
   81 
   82         fprintf (gf_log_logfile, "\n");
   83         fflush (gf_log_logfile);
   84 }
   85 #endif
   86 
   87 int
   88 glusterfs_read_secure_access_file(void)
   89 {
   90     FILE *fp = NULL;
   91     char line[100] = {
   92         0,
   93     };
   94     int cert_depth = 1; /* Default SSL CERT DEPTH */
   95     regex_t regcmpl;
   96     char *key = {"^option transport.socket.ssl-cert-depth"};
   97     char keyval[50] = {
   98         0,
   99     };
  100     int start = 0, end = 0, copy_len = 0;
  101     regmatch_t result[1] = {{0}};
  102 
  103     fp = fopen(SECURE_ACCESS_FILE, "r");
  104     if (!fp)
  105         goto out;
  106 
  107     /* Check if any line matches with key */
  108     while (fgets(line, sizeof(line), fp) != NULL) {
  109         if (regcomp(&regcmpl, key, REG_EXTENDED)) {
  110             goto out;
  111         }
  112         if (!regexec(&regcmpl, line, 1, result, 0)) {
  113             start = result[0].rm_so;
  114             end = result[0].rm_eo;
  115             copy_len = end - start;
  116             gf_strncpy(keyval, line + copy_len, sizeof(keyval));
  117             if (keyval[0]) {
  118                 cert_depth = atoi(keyval);
  119                 if (cert_depth == 0)
  120                     cert_depth = 1; /* Default SSL CERT DEPTH */
  121                 break;
  122             }
  123         }
  124         regfree(&regcmpl);
  125     }
  126 
  127 out:
  128     if (fp)
  129         fclose(fp);
  130     return cert_depth;
  131 }
  132 
  133 xlator_t *
  134 glusterfs_get_last_xlator(glusterfs_graph_t *graph)
  135 {
  136     xlator_t *trav = graph->first;
  137     if (!trav)
  138         return NULL;
  139 
  140     while (trav->next)
  141         trav = trav->next;
  142 
  143     return trav;
  144 }
  145 
  146 xlator_t *
  147 glusterfs_mux_xlator_unlink(xlator_t *pxl, xlator_t *cxl)
  148 {
  149     xlator_list_t *unlink = NULL;
  150     xlator_list_t *prev = NULL;
  151     xlator_list_t **tmp = NULL;
  152     xlator_t *next_child = NULL;
  153     xlator_t *xl = NULL;
  154 
  155     for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next) {
  156         if ((*tmp)->xlator == cxl) {
  157             unlink = *tmp;
  158             *tmp = (*tmp)->next;
  159             if (*tmp)
  160                 next_child = (*tmp)->xlator;
  161             break;
  162         }
  163         prev = *tmp;
  164     }
  165 
  166     if (!prev)
  167         xl = pxl;
  168     else if (prev->xlator)
  169         xl = prev->xlator->graph->last_xl;
  170 
  171     if (xl)
  172         xl->next = next_child;
  173     if (next_child)
  174         next_child->prev = xl;
  175 
  176     GF_FREE(unlink);
  177     return next_child;
  178 }
  179 
  180 int
  181 glusterfs_xlator_link(xlator_t *pxl, xlator_t *cxl)
  182 {
  183     xlator_list_t *xlchild = NULL;
  184     xlator_list_t *xlparent = NULL;
  185     xlator_list_t **tmp = NULL;
  186 
  187     xlparent = (void *)GF_CALLOC(1, sizeof(*xlparent),
  188                                  gf_common_mt_xlator_list_t);
  189     if (!xlparent)
  190         return -1;
  191 
  192     xlchild = (void *)GF_CALLOC(1, sizeof(*xlchild),
  193                                 gf_common_mt_xlator_list_t);
  194     if (!xlchild) {
  195         GF_FREE(xlparent);
  196 
  197         return -1;
  198     }
  199 
  200     xlparent->xlator = pxl;
  201     for (tmp = &cxl->parents; *tmp; tmp = &(*tmp)->next)
  202         ;
  203     *tmp = xlparent;
  204 
  205     xlchild->xlator = cxl;
  206     for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next)
  207         ;
  208     *tmp = xlchild;
  209 
  210     return 0;
  211 }
  212 
  213 void
  214 glusterfs_graph_set_first(glusterfs_graph_t *graph, xlator_t *xl)
  215 {
  216     xl->next = graph->first;
  217     if (graph->first)
  218         ((xlator_t *)graph->first)->prev = xl;
  219     graph->first = xl;
  220 
  221     graph->xl_count++;
  222     xl->xl_id = graph->xl_count;
  223 }
  224 
  225 int
  226 glusterfs_graph_insert(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx,
  227                        const char *type, const char *name,
  228                        gf_boolean_t autoload)
  229 {
  230     xlator_t *ixl = NULL;
  231 
  232     if (!ctx->master) {
  233         gf_msg("glusterfs", GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR,
  234                "volume \"%s\" can be added from command line only "
  235                "on client side",
  236                type);
  237 
  238         return -1;
  239     }
  240 
  241     ixl = GF_CALLOC(1, sizeof(*ixl), gf_common_mt_xlator_t);
  242     if (!ixl)
  243         return -1;
  244 
  245     ixl->ctx = ctx;
  246     ixl->graph = graph;
  247     ixl->options = dict_new();
  248     if (!ixl->options)
  249         goto err;
  250 
  251     ixl->name = gf_strdup(name);
  252     if (!ixl->name)
  253         goto err;
  254 
  255     ixl->is_autoloaded = autoload;
  256 
  257     if (xlator_set_type(ixl, type) == -1) {
  258         gf_msg("glusterfs", GF_LOG_ERROR, 0, LG_MSG_INIT_FAILED,
  259                "%s (%s) initialization failed", name, type);
  260         return -1;
  261     }
  262 
  263     if (glusterfs_xlator_link(ixl, graph->top) == -1)
  264         goto err;
  265     glusterfs_graph_set_first(graph, ixl);
  266     graph->top = ixl;
  267 
  268     return 0;
  269 err:
  270     xlator_destroy(ixl);
  271     return -1;
  272 }
  273 
  274 int
  275 glusterfs_graph_acl(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
  276 {
  277     int ret = 0;
  278     cmd_args_t *cmd_args = NULL;
  279 
  280     cmd_args = &ctx->cmd_args;
  281 
  282     if (!cmd_args->acl)
  283         return 0;
  284 
  285     ret = glusterfs_graph_insert(graph, ctx, "system/posix-acl",
  286                                  "posix-acl-autoload", 1);
  287     return ret;
  288 }
  289 
  290 int
  291 glusterfs_graph_worm(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
  292 {
  293     int ret = 0;
  294     cmd_args_t *cmd_args = NULL;
  295 
  296     cmd_args = &ctx->cmd_args;
  297 
  298     if (!cmd_args->worm)
  299         return 0;
  300 
  301     ret = glusterfs_graph_insert(graph, ctx, "features/worm", "worm-autoload",
  302                                  1);
  303     return ret;
  304 }
  305 
  306 int
  307 glusterfs_graph_meta(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
  308 {
  309     int ret = 0;
  310 
  311     if (!ctx->master)
  312         return 0;
  313 
  314     ret = glusterfs_graph_insert(graph, ctx, "meta", "meta-autoload", 1);
  315     return ret;
  316 }
  317 
  318 int
  319 glusterfs_graph_mac_compat(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
  320 {
  321     int ret = 0;
  322     cmd_args_t *cmd_args = NULL;
  323 
  324     cmd_args = &ctx->cmd_args;
  325 
  326     if (cmd_args->mac_compat == GF_OPTION_DISABLE)
  327         return 0;
  328 
  329     ret = glusterfs_graph_insert(graph, ctx, "features/mac-compat",
  330                                  "mac-compat-autoload", 1);
  331 
  332     return ret;
  333 }
  334 
  335 int
  336 glusterfs_graph_gfid_access(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
  337 {
  338     int ret = 0;
  339     cmd_args_t *cmd_args = NULL;
  340 
  341     cmd_args = &ctx->cmd_args;
  342 
  343     if (!cmd_args->aux_gfid_mount)
  344         return 0;
  345 
  346     ret = glusterfs_graph_insert(graph, ctx, "features/gfid-access",
  347                                  "gfid-access-autoload", 1);
  348     return ret;
  349 }
  350 
  351 static void
  352 gf_add_cmdline_options(glusterfs_graph_t *graph, cmd_args_t *cmd_args)
  353 {
  354     int ret = 0;
  355     xlator_t *trav = NULL;
  356     xlator_cmdline_option_t *cmd_option = NULL;
  357 
  358     trav = graph->first;
  359 
  360     while (trav) {
  361         list_for_each_entry(cmd_option, &cmd_args->xlator_options, cmd_args)
  362         {
  363             if (!fnmatch(cmd_option->volume, trav->name, FNM_NOESCAPE)) {
  364                 ret = dict_set_str(trav->options, cmd_option->key,
  365                                    cmd_option->value);
  366                 if (ret == 0) {
  367                     gf_msg(trav->name, GF_LOG_TRACE, 0, LG_MSG_VOL_OPTION_ADD,
  368                            "adding option '%s' for "
  369                            "volume '%s' with value '%s'",
  370                            cmd_option->key, trav->name, cmd_option->value);
  371                 } else {
  372                     gf_msg(trav->name, GF_LOG_WARNING, -ret,
  373                            LG_MSG_VOL_OPTION_ADD,
  374                            "adding option '%s' for "
  375                            "volume '%s' failed",
  376                            cmd_option->key, trav->name);
  377                 }
  378             }
  379         }
  380         trav = trav->next;
  381     }
  382 }
  383 
  384 int
  385 glusterfs_graph_validate_options(glusterfs_graph_t *graph)
  386 {
  387     xlator_t *trav = NULL;
  388     int ret = -1;
  389     char *errstr = NULL;
  390 
  391     trav = graph->first;
  392 
  393     while (trav) {
  394         if (list_empty(&trav->volume_options)) {
  395             trav = trav->next;
  396             continue;
  397         }
  398 
  399         ret = xlator_options_validate(trav, trav->options, &errstr);
  400         if (ret) {
  401             gf_msg(trav->name, GF_LOG_ERROR, 0, LG_MSG_VALIDATION_FAILED,
  402                    "validation failed: "
  403                    "%s",
  404                    errstr);
  405             return ret;
  406         }
  407         trav = trav->next;
  408     }
  409 
  410     return 0;
  411 }
  412 
  413 int
  414 glusterfs_graph_init(glusterfs_graph_t *graph)
  415 {
  416     xlator_t *trav = NULL;
  417     int ret = -1;
  418 
  419     trav = graph->first;
  420 
  421     while (trav) {
  422         ret = xlator_init(trav);
  423         if (ret) {
  424             gf_msg(trav->name, GF_LOG_ERROR, 0, LG_MSG_TRANSLATOR_INIT_FAILED,
  425                    "initializing translator failed");
  426             return ret;
  427         }
  428         trav = trav->next;
  429     }
  430 
  431     return 0;
  432 }
  433 
  434 int
  435 glusterfs_graph_deactivate(glusterfs_graph_t *graph)
  436 {
  437     xlator_t *top = NULL;
  438 
  439     if (graph == NULL)
  440         goto out;
  441 
  442     top = graph->top;
  443     xlator_tree_fini(top);
  444 out:
  445     return 0;
  446 }
  447 
  448 static int
  449 _log_if_unknown_option(dict_t *dict, char *key, data_t *value, void *data)
  450 {
  451     volume_option_t *found = NULL;
  452     xlator_t *xl = NULL;
  453 
  454     xl = data;
  455 
  456     found = xlator_volume_option_get(xl, key);
  457 
  458     if (!found) {
  459         gf_msg(xl->name, GF_LOG_DEBUG, 0, LG_MSG_XLATOR_OPTION_INVALID,
  460                "option '%s' is not recognized", key);
  461     }
  462 
  463     return 0;
  464 }
  465 
  466 static void
  467 _xlator_check_unknown_options(xlator_t *xl, void *data)
  468 {
  469     dict_foreach(xl->options, _log_if_unknown_option, xl);
  470 }
  471 
  472 static int
  473 glusterfs_graph_unknown_options(glusterfs_graph_t *graph)
  474 {
  475     xlator_foreach(graph->first, _xlator_check_unknown_options, NULL);
  476     return 0;
  477 }
  478 
  479 static void
  480 fill_uuid(char *uuid, int size, struct timeval tv)
  481 {
  482     char hostname[50] = {
  483         0,
  484     };
  485     char now_str[64];
  486 
  487     if (gethostname(hostname, sizeof(hostname) - 1) != 0) {
  488         gf_msg("graph", GF_LOG_ERROR, errno, LG_MSG_GETHOSTNAME_FAILED,
  489                "gethostname failed");
  490         hostname[sizeof(hostname) - 1] = '\0';
  491     }
  492 
  493     gf_time_fmt(now_str, sizeof now_str, tv.tv_sec, gf_timefmt_dirent);
  494     snprintf(uuid, size, "%s-%d-%s:%" GF_PRI_SUSECONDS, hostname, getpid(),
  495              now_str, tv.tv_usec);
  496 
  497     return;
  498 }
  499 
  500 static int
  501 glusterfs_graph_settop(glusterfs_graph_t *graph, char *volume_name,
  502                        gf_boolean_t exact_match)
  503 {
  504     int ret = -1;
  505     xlator_t *trav = NULL;
  506 
  507     if (!volume_name || !exact_match) {
  508         graph->top = graph->first;
  509         ret = 0;
  510     } else {
  511         for (trav = graph->first; trav; trav = trav->next) {
  512             if (strcmp(trav->name, volume_name) == 0) {
  513                 graph->top = trav;
  514                 ret = 0;
  515                 break;
  516             }
  517         }
  518     }
  519 
  520     return ret;
  521 }
  522 
  523 int
  524 glusterfs_graph_parent_up(glusterfs_graph_t *graph)
  525 {
  526     xlator_t *trav = NULL;
  527     int ret = -1;
  528 
  529     trav = graph->first;
  530 
  531     while (trav) {
  532         if (!xlator_has_parent(trav)) {
  533             ret = xlator_notify(trav, GF_EVENT_PARENT_UP, trav);
  534         }
  535 
  536         if (ret)
  537             break;
  538 
  539         trav = trav->next;
  540     }
  541 
  542     return ret;
  543 }
  544 
  545 int
  546 glusterfs_graph_prepare(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx,
  547                         char *volume_name)
  548 {
  549     xlator_t *trav = NULL;
  550     int ret = 0;
  551 
  552     /* XXX: CHECKSUM */
  553 
  554     /* XXX: attach to -n volname */
  555     /* A '/' in the volume name suggests brick multiplexing is used, find
  556      * the top of the (sub)graph. The volname MUST match the subvol in this
  557      * case. In other cases (like for gfapi) the default top for the
  558      * (sub)graph is ok. */
  559     if (!volume_name) {
  560         /* GlusterD does not pass a volume_name */
  561         ret = glusterfs_graph_settop(graph, volume_name, _gf_false);
  562     } else if (strncmp(volume_name, "/snaps/", 7) == 0) {
  563         /* snap shots have their top xlator named like "/snaps/..."  */
  564         ret = glusterfs_graph_settop(graph, volume_name, _gf_false);
  565     } else if (volume_name[0] == '/') {
  566         /* brick multiplexing passes the brick path */
  567         ret = glusterfs_graph_settop(graph, volume_name, _gf_true);
  568     } else {
  569         ret = glusterfs_graph_settop(graph, volume_name, _gf_false);
  570     }
  571 
  572     if (ret) {
  573         gf_msg("graph", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_ERROR,
  574                "glusterfs graph settop failed");
  575         errno = EINVAL;
  576         return -1;
  577     }
  578 
  579     /* XXX: WORM VOLUME */
  580     ret = glusterfs_graph_worm(graph, ctx);
  581     if (ret) {
  582         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
  583                "glusterfs graph worm failed");
  584         return -1;
  585     }
  586     ret = glusterfs_graph_acl(graph, ctx);
  587     if (ret) {
  588         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
  589                "glusterfs graph ACL failed");
  590         return -1;
  591     }
  592 
  593     /* XXX: MAC COMPAT */
  594     ret = glusterfs_graph_mac_compat(graph, ctx);
  595     if (ret) {
  596         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
  597                "glusterfs graph mac compat failed");
  598         return -1;
  599     }
  600 
  601     /* XXX: gfid-access */
  602     ret = glusterfs_graph_gfid_access(graph, ctx);
  603     if (ret) {
  604         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
  605                "glusterfs graph 'gfid-access' failed");
  606         return -1;
  607     }
  608 
  609     /* XXX: topmost xlator */
  610     ret = glusterfs_graph_meta(graph, ctx);
  611     if (ret) {
  612         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
  613                "glusterfs graph meta failed");
  614         return -1;
  615     }
  616 
  617     /* XXX: this->ctx setting */
  618     for (trav = graph->first; trav; trav = trav->next) {
  619         trav->ctx = ctx;
  620     }
  621 
  622     /* XXX: DOB setting */
  623     gettimeofday(&graph->dob, NULL);
  624 
  625     fill_uuid(graph->graph_uuid, sizeof(graph->graph_uuid), graph->dob);
  626 
  627     graph->id = ctx->graph_id++;
  628 
  629     /* XXX: --xlator-option additions */
  630     gf_add_cmdline_options(graph, &ctx->cmd_args);
  631 
  632     return 0;
  633 }
  634 
  635 static xlator_t *
  636 glusterfs_root(glusterfs_graph_t *graph)
  637 {
  638     return graph->first;
  639 }
  640 
  641 static int
  642 glusterfs_is_leaf(xlator_t *xl)
  643 {
  644     int ret = 0;
  645 
  646     if (!xl->children)
  647         ret = 1;
  648 
  649     return ret;
  650 }
  651 
  652 static uint32_t
  653 glusterfs_count_leaves(xlator_t *xl)
  654 {
  655     int n = 0;
  656     xlator_list_t *list = NULL;
  657 
  658     if (glusterfs_is_leaf(xl))
  659         n = 1;
  660     else
  661         for (list = xl->children; list; list = list->next)
  662             n += glusterfs_count_leaves(list->xlator);
  663 
  664     return n;
  665 }
  666 
  667 int
  668 glusterfs_get_leaf_count(glusterfs_graph_t *graph)
  669 {
  670     return graph->leaf_count;
  671 }
  672 
  673 static int
  674 _glusterfs_leaf_position(xlator_t *tgt, int *id, xlator_t *xl)
  675 {
  676     xlator_list_t *list = NULL;
  677     int found = 0;
  678 
  679     if (xl == tgt)
  680         found = 1;
  681     else if (glusterfs_is_leaf(xl))
  682         *id += 1;
  683     else
  684         for (list = xl->children; !found && list; list = list->next)
  685             found = _glusterfs_leaf_position(tgt, id, list->xlator);
  686 
  687     return found;
  688 }
  689 
  690 int
  691 glusterfs_leaf_position(xlator_t *tgt)
  692 {
  693     xlator_t *root = NULL;
  694     int pos = 0;
  695 
  696     root = glusterfs_root(tgt->graph);
  697 
  698     if (!_glusterfs_leaf_position(tgt, &pos, root))
  699         pos = -1;
  700 
  701     return pos;
  702 }
  703 
  704 static int
  705 _glusterfs_reachable_leaves(xlator_t *base, xlator_t *xl, dict_t *leaves)
  706 {
  707     xlator_list_t *list = NULL;
  708     int err = 1;
  709     int pos = 0;
  710     char *strpos = NULL;
  711 
  712     if (glusterfs_is_leaf(xl)) {
  713         pos = glusterfs_leaf_position(xl);
  714         if (pos < 0)
  715             goto out;
  716 
  717         err = gf_asprintf(&strpos, "%d", pos);
  718 
  719         if (err >= 0) {
  720             err = dict_set_static_ptr(leaves, strpos, base);
  721             GF_FREE(strpos);
  722         }
  723     } else {
  724         for (err = 0, list = xl->children; !err && list; list = list->next)
  725             err = _glusterfs_reachable_leaves(base, list->xlator, leaves);
  726     }
  727 
  728 out:
  729     return err;
  730 }
  731 
  732 /*
  733  * This function determines which leaves are children (or grandchildren)
  734  * of the given base. The base may have multiple sub volumes. Each sub
  735  * volumes in turn may have sub volumes.. until the leaves are reached.
  736  * Each leaf is numbered 1,2,3,...etc.
  737  *
  738  * The base translator calls this function to see which of *its* subvolumes
  739  * it would forward an FOP to, to *get to* a particular leaf.
  740  * That information is built into the "leaves" dictionary.
  741  * key:destination leaf# -> value:base subvolume xlator.
  742  */
  743 
  744 int
  745 glusterfs_reachable_leaves(xlator_t *base, dict_t *leaves)
  746 {
  747     xlator_list_t *list = NULL;
  748     int err = 0;
  749 
  750     for (list = base->children; !err && list; list = list->next)
  751         err = _glusterfs_reachable_leaves(list->xlator, list->xlator, leaves);
  752 
  753     return err;
  754 }
  755 
  756 int
  757 glusterfs_graph_activate(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
  758 {
  759     int ret = 0;
  760     xlator_t *root = NULL;
  761 
  762     root = glusterfs_root(graph);
  763 
  764     graph->leaf_count = glusterfs_count_leaves(root);
  765 
  766     /* XXX: all xlator options validation */
  767     ret = glusterfs_graph_validate_options(graph);
  768     if (ret) {
  769         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_VALIDATION_FAILED,
  770                "validate options failed");
  771         return ret;
  772     }
  773 
  774     /* XXX: perform init () */
  775     ret = glusterfs_graph_init(graph);
  776     if (ret) {
  777         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_INIT_FAILED,
  778                "init failed");
  779         return ret;
  780     }
  781 
  782     ret = glusterfs_graph_unknown_options(graph);
  783     if (ret) {
  784         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_UNKNOWN_OPTIONS_FAILED,
  785                "unknown options "
  786                "failed");
  787         return ret;
  788     }
  789 
  790     /* XXX: log full graph (_gf_dump_details) */
  791 
  792     list_add(&graph->list, &ctx->graphs);
  793     ctx->active = graph;
  794 
  795     /* XXX: attach to master and set active pointer */
  796     if (ctx->master) {
  797         ret = xlator_notify(ctx->master, GF_EVENT_GRAPH_NEW, graph);
  798         if (ret) {
  799             gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED,
  800                    "graph new notification failed");
  801             return ret;
  802         }
  803         ((xlator_t *)ctx->master)->next = graph->top;
  804     }
  805 
  806     /* XXX: perform parent up */
  807     ret = glusterfs_graph_parent_up(graph);
  808     if (ret) {
  809         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED,
  810                "parent up notification failed");
  811         return ret;
  812     }
  813 
  814     return 0;
  815 }
  816 
  817 int
  818 xlator_equal_rec(xlator_t *xl1, xlator_t *xl2)
  819 {
  820     xlator_list_t *trav1 = NULL;
  821     xlator_list_t *trav2 = NULL;
  822     int ret = 0;
  823 
  824     if (xl1 == NULL || xl2 == NULL) {
  825         gf_msg_debug("xlator", 0, "invalid argument");
  826         return -1;
  827     }
  828 
  829     trav1 = xl1->children;
  830     trav2 = xl2->children;
  831 
  832     while (trav1 && trav2) {
  833         ret = xlator_equal_rec(trav1->xlator, trav2->xlator);
  834         if (ret) {
  835             gf_msg_debug("glusterfsd-mgmt", 0,
  836                          "xlators children "
  837                          "not equal");
  838             goto out;
  839         }
  840 
  841         trav1 = trav1->next;
  842         trav2 = trav2->next;
  843     }
  844 
  845     if (trav1 || trav2) {
  846         ret = -1;
  847         goto out;
  848     }
  849 
  850     if (strcmp(xl1->name, xl2->name)) {
  851         ret = -1;
  852         goto out;
  853     }
  854 
  855     /* type could have changed even if xlator names match,
  856        e.g cluster/distribute and cluster/nufa share the same
  857        xlator name
  858     */
  859     if (strcmp(xl1->type, xl2->type)) {
  860         ret = -1;
  861         goto out;
  862     }
  863 out:
  864     return ret;
  865 }
  866 
  867 gf_boolean_t
  868 is_graph_topology_equal(glusterfs_graph_t *graph1, glusterfs_graph_t *graph2)
  869 {
  870     xlator_t *trav1 = NULL;
  871     xlator_t *trav2 = NULL;
  872     gf_boolean_t ret = _gf_true;
  873     xlator_list_t *ltrav;
  874 
  875     trav1 = graph1->first;
  876     trav2 = graph2->first;
  877 
  878     if (strcmp(trav2->type, "protocol/server") == 0) {
  879         trav2 = trav2->children->xlator;
  880         for (ltrav = trav1->children; ltrav; ltrav = ltrav->next) {
  881             trav1 = ltrav->xlator;
  882             if (!trav1->cleanup_starting && !strcmp(trav1->name, trav2->name)) {
  883                 break;
  884             }
  885         }
  886         if (!ltrav) {
  887             return _gf_false;
  888         }
  889     }
  890 
  891     ret = xlator_equal_rec(trav1, trav2);
  892 
  893     if (ret) {
  894         gf_msg_debug("glusterfsd-mgmt", 0, "graphs are not equal");
  895         ret = _gf_false;
  896         goto out;
  897     }
  898 
  899     ret = _gf_true;
  900     gf_msg_debug("glusterfsd-mgmt", 0, "graphs are equal");
  901 
  902 out:
  903     return ret;
  904 }
  905 
  906 /* Function has 3types of return value 0, -ve , 1
  907  *   return 0          =======> reconfiguration of options has succeeded
  908  *   return 1          =======> the graph has to be reconstructed and all the
  909  * xlators should be inited return -1(or -ve) =======> Some Internal Error
  910  * occurred during the operation
  911  */
  912 int
  913 glusterfs_volfile_reconfigure(FILE *newvolfile_fp, glusterfs_ctx_t *ctx)
  914 {
  915     glusterfs_graph_t *oldvolfile_graph = NULL;
  916     glusterfs_graph_t *newvolfile_graph = NULL;
  917 
  918     int ret = -1;
  919 
  920     if (!ctx) {
  921         gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
  922                "ctx is NULL");
  923         goto out;
  924     }
  925 
  926     oldvolfile_graph = ctx->active;
  927     if (!oldvolfile_graph) {
  928         ret = 1;
  929         goto out;
  930     }
  931 
  932     newvolfile_graph = glusterfs_graph_construct(newvolfile_fp);
  933 
  934     if (!newvolfile_graph) {
  935         goto out;
  936     }
  937 
  938     glusterfs_graph_prepare(newvolfile_graph, ctx, ctx->cmd_args.volume_name);
  939 
  940     if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) {
  941         ret = 1;
  942         gf_msg_debug("glusterfsd-mgmt", 0,
  943                      "Graph topology not "
  944                      "equal(should call INIT)");
  945         goto out;
  946     }
  947 
  948     gf_msg_debug("glusterfsd-mgmt", 0,
  949                  "Only options have changed in the"
  950                  " new graph");
  951 
  952     ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph);
  953     if (ret) {
  954         gf_msg_debug("glusterfsd-mgmt", 0,
  955                      "Could not reconfigure "
  956                      "new options in old graph");
  957         goto out;
  958     }
  959 
  960     ret = 0;
  961 out:
  962 
  963     if (newvolfile_graph)
  964         glusterfs_graph_destroy(newvolfile_graph);
  965 
  966     return ret;
  967 }
  968 
  969 /* This function need to remove. This added to support gfapi volfile
  970  * reconfigure.
  971  */
  972 
  973 int
  974 gf_volfile_reconfigure(int oldvollen, FILE *newvolfile_fp, glusterfs_ctx_t *ctx,
  975                        const char *oldvolfile)
  976 {
  977     glusterfs_graph_t *oldvolfile_graph = NULL;
  978     glusterfs_graph_t *newvolfile_graph = NULL;
  979     FILE *oldvolfile_fp = NULL;
  980     /*Since the function mkstemp() replaces XXXXXX,
  981      * assigning it to a variable
  982      */
  983     char temp_file[] = "/tmp/temp_vol_file_XXXXXX";
  984     gf_boolean_t active_graph_found = _gf_true;
  985 
  986     int ret = -1;
  987     int u_ret = -1;
  988     int file_desc = -1;
  989 
  990     if (!oldvollen) {
  991         ret = 1;  // Has to call INIT for the whole graph
  992         goto out;
  993     }
  994 
  995     if (!ctx) {
  996         gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
  997                "ctx is NULL");
  998         goto out;
  999     }
 1000 
 1001     oldvolfile_graph = ctx->active;
 1002     if (!oldvolfile_graph) {
 1003         active_graph_found = _gf_false;
 1004         gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_ACTIVE_GRAPH_NULL,
 1005                "glusterfs_ctx->active is NULL");
 1006 
 1007         /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */
 1008         file_desc = mkstemp(temp_file);
 1009         if (file_desc < 0) {
 1010             gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, errno,
 1011                    LG_MSG_TMPFILE_CREATE_FAILED,
 1012                    "Unable to "
 1013                    "create temporary volfile");
 1014             goto out;
 1015         }
 1016 
 1017         /*Calling unlink so that when the file is closed or program
 1018          *terminates the tempfile is deleted.
 1019          */
 1020         u_ret = sys_unlink(temp_file);
 1021 
 1022         if (u_ret < 0) {
 1023             gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, errno,
 1024                    LG_MSG_TMPFILE_DELETE_FAILED,
 1025                    "Temporary file"
 1026                    " delete failed.");
 1027             sys_close(file_desc);
 1028             goto out;
 1029         }
 1030 
 1031         oldvolfile_fp = fdopen(file_desc, "w+b");
 1032         if (!oldvolfile_fp)
 1033             goto out;
 1034 
 1035         fwrite(oldvolfile, oldvollen, 1, oldvolfile_fp);
 1036         fflush(oldvolfile_fp);
 1037         if (ferror(oldvolfile_fp)) {
 1038             goto out;
 1039         }
 1040 
 1041         oldvolfile_graph = glusterfs_graph_construct(oldvolfile_fp);
 1042         if (!oldvolfile_graph)
 1043             goto out;
 1044     }
 1045 
 1046     newvolfile_graph = glusterfs_graph_construct(newvolfile_fp);
 1047     if (!newvolfile_graph) {
 1048         goto out;
 1049     }
 1050 
 1051     glusterfs_graph_prepare(newvolfile_graph, ctx, ctx->cmd_args.volume_name);
 1052 
 1053     if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) {
 1054         ret = 1;
 1055         gf_msg_debug("glusterfsd-mgmt", 0,
 1056                      "Graph topology not "
 1057                      "equal(should call INIT)");
 1058         goto out;
 1059     }
 1060 
 1061     gf_msg_debug("glusterfsd-mgmt", 0,
 1062                  "Only options have changed in the"
 1063                  " new graph");
 1064 
 1065     /* */
 1066     ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph);
 1067     if (ret) {
 1068         gf_msg_debug("glusterfsd-mgmt", 0,
 1069                      "Could not reconfigure "
 1070                      "new options in old graph");
 1071         goto out;
 1072     }
 1073 
 1074     ret = 0;
 1075 out:
 1076     if (oldvolfile_fp)
 1077         fclose(oldvolfile_fp);
 1078 
 1079     /*  Do not simply destroy the old graph here. If the oldgraph
 1080         is constructed here in this function itself instead of getting
 1081         it from ctx->active (which happens only of ctx->active is NULL),
 1082         then destroy the old graph. If some i/o is still happening in
 1083         the old graph and the old graph is obtained from ctx->active,
 1084         then destroying the graph will cause problems.
 1085     */
 1086     if (!active_graph_found && oldvolfile_graph)
 1087         glusterfs_graph_destroy(oldvolfile_graph);
 1088     if (newvolfile_graph)
 1089         glusterfs_graph_destroy(newvolfile_graph);
 1090 
 1091     return ret;
 1092 }
 1093 
 1094 int
 1095 glusterfs_graph_reconfigure(glusterfs_graph_t *oldgraph,
 1096                             glusterfs_graph_t *newgraph)
 1097 {
 1098     xlator_t *old_xl = NULL;
 1099     xlator_t *new_xl = NULL;
 1100     xlator_list_t *trav;
 1101 
 1102     GF_ASSERT(oldgraph);
 1103     GF_ASSERT(newgraph);
 1104 
 1105     old_xl = oldgraph->first;
 1106     while (old_xl->is_autoloaded) {
 1107         old_xl = old_xl->children->xlator;
 1108     }
 1109 
 1110     new_xl = newgraph->first;
 1111     while (new_xl->is_autoloaded) {
 1112         new_xl = new_xl->children->xlator;
 1113     }
 1114 
 1115     if (strcmp(old_xl->type, "protocol/server") != 0) {
 1116         return xlator_tree_reconfigure(old_xl, new_xl);
 1117     }
 1118 
 1119     /* Some options still need to be handled by the server translator. */
 1120     if (old_xl->reconfigure) {
 1121         old_xl->reconfigure(old_xl, new_xl->options);
 1122     }
 1123 
 1124     (void)copy_opts_to_child(new_xl, FIRST_CHILD(new_xl), "*auth*");
 1125     new_xl = FIRST_CHILD(new_xl);
 1126 
 1127     for (trav = old_xl->children; trav; trav = trav->next) {
 1128         if (!trav->xlator->cleanup_starting &&
 1129             !strcmp(trav->xlator->name, new_xl->name)) {
 1130             return xlator_tree_reconfigure(trav->xlator, new_xl);
 1131         }
 1132     }
 1133 
 1134     return -1;
 1135 }
 1136 
 1137 int
 1138 glusterfs_graph_destroy_residual(glusterfs_graph_t *graph)
 1139 {
 1140     int ret = -1;
 1141 
 1142     if (graph == NULL)
 1143         return ret;
 1144 
 1145     ret = xlator_tree_free_memacct(graph->first);
 1146 
 1147     list_del_init(&graph->list);
 1148     pthread_mutex_destroy(&graph->mutex);
 1149     pthread_cond_destroy(&graph->child_down_cond);
 1150     GF_FREE(graph);
 1151 
 1152     return ret;
 1153 }
 1154 
 1155 /* This function destroys all the xlator members except for the
 1156  * xlator strcuture and its mem accounting field.
 1157  *
 1158  * If otherwise, it would destroy the master xlator object as well
 1159  * its mem accounting, which would mean after calling glusterfs_graph_destroy()
 1160  * there cannot be any reference to GF_FREE() from the master xlator, this is
 1161  * not possible because of the following dependencies:
 1162  * - glusterfs_ctx_t will have mem pools allocated by the master xlators
 1163  * - xlator objects will have references to those mem pools(g: dict)
 1164  *
 1165  * Ordering the freeing in any of the order will also not solve the dependency:
 1166  * - Freeing xlator objects(including memory accounting) before mem pools
 1167  *   destruction will mean not use GF_FREE while destroying mem pools.
 1168  * - Freeing mem pools and then destroying xlator objects would lead to crashes
 1169  *   when xlator tries to unref dict or other mem pool objects.
 1170  *
 1171  * Hence the way chosen out of this interdependency is to split xlator object
 1172  * free into two stages:
 1173  * - Free all the xlator members excpet for its mem accounting structure
 1174  * - Free all the mem accouting structures of xlator along with the xlator
 1175  *   object itself.
 1176  */
 1177 int
 1178 glusterfs_graph_destroy(glusterfs_graph_t *graph)
 1179 {
 1180     int ret = 0;
 1181 
 1182     GF_VALIDATE_OR_GOTO("graph", graph, out);
 1183 
 1184     ret = xlator_tree_free_members(graph->first);
 1185 
 1186     ret = glusterfs_graph_destroy_residual(graph);
 1187 out:
 1188     return ret;
 1189 }
 1190 
 1191 int
 1192 glusterfs_graph_fini(glusterfs_graph_t *graph)
 1193 {
 1194     xlator_t *trav = NULL;
 1195 
 1196     trav = graph->first;
 1197 
 1198     while (trav) {
 1199         if (trav->init_succeeded) {
 1200             trav->cleanup_starting = 1;
 1201             trav->fini(trav);
 1202             if (trav->local_pool) {
 1203                 mem_pool_destroy(trav->local_pool);
 1204                 trav->local_pool = NULL;
 1205             }
 1206             if (trav->itable) {
 1207                 inode_table_destroy(trav->itable);
 1208                 trav->itable = NULL;
 1209             }
 1210             trav->init_succeeded = 0;
 1211         }
 1212         trav = trav->next;
 1213     }
 1214 
 1215     return 0;
 1216 }
 1217 
 1218 int
 1219 glusterfs_graph_attach(glusterfs_graph_t *orig_graph, char *path,
 1220                        glusterfs_graph_t **newgraph)
 1221 {
 1222     xlator_t *this = THIS;
 1223     FILE *fp;
 1224     glusterfs_graph_t *graph;
 1225     xlator_t *xl;
 1226     char *volfile_id = NULL;
 1227     char *volfile_content = NULL;
 1228     struct stat stbuf = {
 1229         0,
 1230     };
 1231     size_t file_len = -1;
 1232     gf_volfile_t *volfile_obj = NULL;
 1233     int ret = -1;
 1234     char sha256_hash[SHA256_DIGEST_LENGTH] = {
 1235         0,
 1236     };
 1237 
 1238     if (!orig_graph) {
 1239         return -EINVAL;
 1240     }
 1241 
 1242     ret = sys_stat(path, &stbuf);
 1243     if (ret < 0) {
 1244         gf_log(THIS->name, GF_LOG_ERROR, "Unable to stat %s (%s)", path,
 1245                strerror(errno));
 1246         return -EINVAL;
 1247     }
 1248 
 1249     file_len = stbuf.st_size;
 1250     volfile_content = GF_MALLOC(file_len + 1, gf_common_mt_char);
 1251     if (!volfile_content)
 1252         return -ENOMEM;
 1253 
 1254     fp = fopen(path, "r");
 1255     if (!fp) {
 1256         gf_log(THIS->name, GF_LOG_WARNING, "oops, %s disappeared on us", path);
 1257         GF_FREE(volfile_content);
 1258         return -EIO;
 1259     }
 1260 
 1261     ret = fread(volfile_content, sizeof(char), file_len, fp);
 1262     if (ret == file_len) {
 1263         glusterfs_compute_sha256((const unsigned char *)volfile_content,
 1264                                  file_len, sha256_hash);
 1265     } else {
 1266         gf_log(THIS->name, GF_LOG_ERROR,
 1267                "read failed on path %s. File size=%" GF_PRI_SIZET
 1268                "read size=%d",
 1269                path, file_len, ret);
 1270         GF_FREE(volfile_content);
 1271         fclose(fp);
 1272         return -EIO;
 1273     }
 1274 
 1275     GF_FREE(volfile_content);
 1276 
 1277     graph = glusterfs_graph_construct(fp);
 1278     fclose(fp);
 1279     if (!graph) {
 1280         gf_log(this->name, GF_LOG_WARNING, "could not create graph from %s",
 1281                path);
 1282         return -EIO;
 1283     }
 1284 
 1285     /*
 1286      * If there's a server translator on top, we want whatever's below
 1287      * that.
 1288      */
 1289     xl = graph->first;
 1290     if (strcmp(xl->type, "protocol/server") == 0) {
 1291         (void)copy_opts_to_child(xl, FIRST_CHILD(xl), "*auth*");
 1292         xl = FIRST_CHILD(xl);
 1293     }
 1294     graph->first = xl;
 1295     *newgraph = graph;
 1296 
 1297     volfile_id = strstr(path, "/snaps/");
 1298     if (!volfile_id) {
 1299         volfile_id = rindex(path, '/');
 1300         if (volfile_id) {
 1301             ++volfile_id;
 1302         }
 1303     }
 1304     if (volfile_id) {
 1305         xl->volfile_id = gf_strdup(volfile_id);
 1306         /* There's a stray ".vol" at the end. */
 1307         xl->volfile_id[strlen(xl->volfile_id) - 4] = '\0';
 1308     }
 1309 
 1310     /* TODO memory leaks everywhere need to free graph in case of error */
 1311     if (glusterfs_graph_prepare(graph, this->ctx, xl->name)) {
 1312         gf_log(this->name, GF_LOG_WARNING,
 1313                "failed to prepare graph for xlator %s", xl->name);
 1314         return -EIO;
 1315     } else if (glusterfs_graph_init(graph)) {
 1316         gf_log(this->name, GF_LOG_WARNING,
 1317                "failed to initialize graph for xlator %s", xl->name);
 1318         return -EIO;
 1319     } else if (glusterfs_xlator_link(orig_graph->top, graph->top)) {
 1320         gf_log(this->name, GF_LOG_WARNING,
 1321                "failed to link the graphs for xlator %s ", xl->name);
 1322         return -EIO;
 1323     }
 1324 
 1325     if (!volfile_obj) {
 1326         volfile_obj = GF_CALLOC(1, sizeof(gf_volfile_t), gf_common_volfile_t);
 1327         if (!volfile_obj) {
 1328             return -EIO;
 1329         }
 1330     }
 1331 
 1332     INIT_LIST_HEAD(&volfile_obj->volfile_list);
 1333     snprintf(volfile_obj->vol_id, sizeof(volfile_obj->vol_id), "%s",
 1334              xl->volfile_id);
 1335     memcpy(volfile_obj->volfile_checksum, sha256_hash,
 1336            sizeof(volfile_obj->volfile_checksum));
 1337     list_add(&volfile_obj->volfile_list, &this->ctx->volfile_list);
 1338 
 1339     return 0;
 1340 }
 1341 int
 1342 glusterfs_muxsvc_cleanup_parent(glusterfs_ctx_t *ctx,
 1343                                 glusterfs_graph_t *parent_graph)
 1344 {
 1345     if (parent_graph) {
 1346         if (parent_graph->first) {
 1347             xlator_destroy(parent_graph->first);
 1348         }
 1349         ctx->active = NULL;
 1350         GF_FREE(parent_graph);
 1351         parent_graph = NULL;
 1352     }
 1353     return 0;
 1354 }
 1355 
 1356 void *
 1357 glusterfs_graph_cleanup(void *arg)
 1358 {
 1359     glusterfs_graph_t *graph = NULL;
 1360     glusterfs_ctx_t *ctx = THIS->ctx;
 1361     int ret = -1;
 1362     graph = arg;
 1363 
 1364     if (!graph)
 1365         return NULL;
 1366 
 1367     /* To destroy the graph, fitst sent a GF_EVENT_PARENT_DOWN
 1368      * Then wait for GF_EVENT_CHILD_DOWN to get on the top
 1369      * xl. Once we have GF_EVENT_CHILD_DOWN event, then proceed
 1370      * to fini.
 1371      *
 1372      * During fini call, this will take a last unref on rpc and
 1373      * rpc_transport_object.
 1374      */
 1375     if (graph->first)
 1376         default_notify(graph->first, GF_EVENT_PARENT_DOWN, graph->first);
 1377 
 1378     ret = pthread_mutex_lock(&graph->mutex);
 1379     if (ret != 0) {
 1380         gf_msg("glusterfs", GF_LOG_ERROR, EAGAIN, LG_MSG_GRAPH_CLEANUP_FAILED,
 1381                "Failed to acquire a lock");
 1382         goto out;
 1383     }
 1384     /* check and wait for CHILD_DOWN for top xlator*/
 1385     while (graph->used) {
 1386         ret = pthread_cond_wait(&graph->child_down_cond, &graph->mutex);
 1387         if (ret != 0)
 1388             gf_msg("glusterfs", GF_LOG_INFO, 0, LG_MSG_GRAPH_CLEANUP_FAILED,
 1389                    "cond wait failed ");
 1390     }
 1391 
 1392     ret = pthread_mutex_unlock(&graph->mutex);
 1393     if (ret != 0) {
 1394         gf_msg("glusterfs", GF_LOG_ERROR, EAGAIN, LG_MSG_GRAPH_CLEANUP_FAILED,
 1395                "Failed to release a lock");
 1396     }
 1397 
 1398     /* Though we got a child down on top xlator, we have to wait until
 1399      * all the notifier to exit. Because there should not be any threads
 1400      * that access xl variables.
 1401      */
 1402     pthread_mutex_lock(&ctx->notify_lock);
 1403     {
 1404         while (ctx->notifying)
 1405             pthread_cond_wait(&ctx->notify_cond, &ctx->notify_lock);
 1406     }
 1407     pthread_mutex_unlock(&ctx->notify_lock);
 1408 
 1409     pthread_mutex_lock(&ctx->cleanup_lock);
 1410     {
 1411         glusterfs_graph_fini(graph);
 1412         glusterfs_graph_destroy(graph);
 1413     }
 1414     pthread_mutex_unlock(&ctx->cleanup_lock);
 1415 out:
 1416     return NULL;
 1417 }
 1418 
 1419 glusterfs_graph_t *
 1420 glusterfs_muxsvc_setup_parent_graph(glusterfs_ctx_t *ctx, char *name,
 1421                                     char *type)
 1422 {
 1423     glusterfs_graph_t *parent_graph = NULL;
 1424     xlator_t *ixl = NULL;
 1425     int ret = -1;
 1426     parent_graph = GF_CALLOC(1, sizeof(*parent_graph),
 1427                              gf_common_mt_glusterfs_graph_t);
 1428     if (!parent_graph)
 1429         goto out;
 1430 
 1431     INIT_LIST_HEAD(&parent_graph->list);
 1432 
 1433     ctx->active = parent_graph;
 1434     ixl = GF_CALLOC(1, sizeof(*ixl), gf_common_mt_xlator_t);
 1435     if (!ixl)
 1436         goto out;
 1437 
 1438     ixl->ctx = ctx;
 1439     ixl->graph = parent_graph;
 1440     ixl->options = dict_new();
 1441     if (!ixl->options)
 1442         goto out;
 1443 
 1444     ixl->name = gf_strdup(name);
 1445     if (!ixl->name)
 1446         goto out;
 1447 
 1448     ixl->is_autoloaded = 1;
 1449 
 1450     if (xlator_set_type(ixl, type) == -1) {
 1451         gf_msg("glusterfs", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
 1452                "%s (%s) set type failed", name, type);
 1453         goto out;
 1454     }
 1455 
 1456     glusterfs_graph_set_first(parent_graph, ixl);
 1457     parent_graph->top = ixl;
 1458     ixl = NULL;
 1459 
 1460     gettimeofday(&parent_graph->dob, NULL);
 1461     fill_uuid(parent_graph->graph_uuid, 128, parent_graph->dob);
 1462     parent_graph->id = ctx->graph_id++;
 1463     ret = 0;
 1464 out:
 1465     if (ixl)
 1466         xlator_destroy(ixl);
 1467 
 1468     if (ret) {
 1469         glusterfs_muxsvc_cleanup_parent(ctx, parent_graph);
 1470         parent_graph = NULL;
 1471     }
 1472     return parent_graph;
 1473 }
 1474 
 1475 int
 1476 glusterfs_svc_mux_pidfile_cleanup(gf_volfile_t *volfile_obj)
 1477 {
 1478     if (!volfile_obj || !volfile_obj->pidfp)
 1479         return 0;
 1480 
 1481     gf_msg_trace("glusterfsd", 0, "pidfile %s cleanup", volfile_obj->vol_id);
 1482 
 1483     lockf(fileno(volfile_obj->pidfp), F_ULOCK, 0);
 1484     fclose(volfile_obj->pidfp);
 1485     volfile_obj->pidfp = NULL;
 1486 
 1487     return 0;
 1488 }
 1489 
 1490 int
 1491 glusterfs_process_svc_detach(glusterfs_ctx_t *ctx, gf_volfile_t *volfile_obj)
 1492 {
 1493     xlator_t *last_xl = NULL;
 1494     glusterfs_graph_t *graph = NULL;
 1495     glusterfs_graph_t *parent_graph = NULL;
 1496     pthread_t clean_graph = {
 1497         0,
 1498     };
 1499     int ret = -1;
 1500     xlator_t *xl = NULL;
 1501 
 1502     if (!ctx || !ctx->active || !volfile_obj)
 1503         goto out;
 1504 
 1505     pthread_mutex_lock(&ctx->cleanup_lock);
 1506     {
 1507         parent_graph = ctx->active;
 1508         graph = volfile_obj->graph;
 1509         if (!graph)
 1510             goto unlock;
 1511         if (graph->first)
 1512             xl = graph->first;
 1513 
 1514         last_xl = graph->last_xl;
 1515         if (last_xl)
 1516             last_xl->next = NULL;
 1517         if (!xl || xl->cleanup_starting)
 1518             goto unlock;
 1519 
 1520         xl->cleanup_starting = 1;
 1521         gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_DETACH_STARTED,
 1522                "detaching child %s", volfile_obj->vol_id);
 1523 
 1524         list_del_init(&volfile_obj->volfile_list);
 1525         glusterfs_mux_xlator_unlink(parent_graph->top, xl);
 1526         glusterfs_svc_mux_pidfile_cleanup(volfile_obj);
 1527         parent_graph->last_xl = glusterfs_get_last_xlator(parent_graph);
 1528         parent_graph->xl_count -= graph->xl_count;
 1529         parent_graph->leaf_count -= graph->leaf_count;
 1530         parent_graph->id++;
 1531         ret = 0;
 1532     }
 1533 unlock:
 1534     pthread_mutex_unlock(&ctx->cleanup_lock);
 1535 out:
 1536     if (!ret) {
 1537         list_del_init(&volfile_obj->volfile_list);
 1538         if (graph) {
 1539             ret = gf_thread_create_detached(
 1540                 &clean_graph, glusterfs_graph_cleanup, graph, "graph_clean");
 1541             if (ret) {
 1542                 gf_msg("glusterfs", GF_LOG_ERROR, EINVAL,
 1543                        LG_MSG_GRAPH_CLEANUP_FAILED,
 1544                        "%s failed to create clean "
 1545                        "up thread",
 1546                        volfile_obj->vol_id);
 1547                 ret = 0;
 1548             }
 1549         }
 1550         GF_FREE(volfile_obj);
 1551     }
 1552     return ret;
 1553 }
 1554 
 1555 int
 1556 glusterfs_svc_mux_pidfile_setup(gf_volfile_t *volfile_obj, const char *pid_file)
 1557 {
 1558     int ret = -1;
 1559     FILE *pidfp = NULL;
 1560 
 1561     if (!pid_file || !volfile_obj)
 1562         goto out;
 1563 
 1564     if (volfile_obj->pidfp) {
 1565         ret = 0;
 1566         goto out;
 1567     }
 1568     pidfp = fopen(pid_file, "a+");
 1569     if (!pidfp) {
 1570         goto out;
 1571     }
 1572     volfile_obj->pidfp = pidfp;
 1573 
 1574     ret = lockf(fileno(pidfp), F_TLOCK, 0);
 1575     if (ret) {
 1576         ret = 0;
 1577         goto out;
 1578     }
 1579 out:
 1580     return ret;
 1581 }
 1582 
 1583 int
 1584 glusterfs_svc_mux_pidfile_update(gf_volfile_t *volfile_obj,
 1585                                  const char *pid_file, pid_t pid)
 1586 {
 1587     int ret = 0;
 1588     FILE *pidfp = NULL;
 1589     int old_pid;
 1590 
 1591     if (!volfile_obj->pidfp) {
 1592         ret = glusterfs_svc_mux_pidfile_setup(volfile_obj, pid_file);
 1593         if (ret == -1)
 1594             goto out;
 1595     }
 1596     pidfp = volfile_obj->pidfp;
 1597     ret = fscanf(pidfp, "%d", &old_pid);
 1598     if (ret <= 0) {
 1599         goto update;
 1600     }
 1601     if (old_pid == pid) {
 1602         ret = 0;
 1603         goto out;
 1604     } else {
 1605         gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED,
 1606                "Old pid=%d found in pidfile %s. Cleaning the old pid and "
 1607                "Updating new pid=%d",
 1608                old_pid, pid_file, pid);
 1609     }
 1610 update:
 1611     ret = sys_ftruncate(fileno(pidfp), 0);
 1612     if (ret) {
 1613         gf_msg("glusterfsd", GF_LOG_ERROR, errno,
 1614                LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED,
 1615                "pidfile %s truncation failed", pid_file);
 1616         goto out;
 1617     }
 1618 
 1619     ret = fprintf(pidfp, "%d\n", pid);
 1620     if (ret <= 0) {
 1621         gf_msg("glusterfsd", GF_LOG_ERROR, errno,
 1622                LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, "pidfile %s write failed",
 1623                pid_file);
 1624         goto out;
 1625     }
 1626 
 1627     ret = fflush(pidfp);
 1628     if (ret) {
 1629         gf_msg("glusterfsd", GF_LOG_ERROR, errno,
 1630                LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, "pidfile %s write failed",
 1631                pid_file);
 1632         goto out;
 1633     }
 1634 out:
 1635     return ret;
 1636 }
 1637 
 1638 int
 1639 glusterfs_update_mux_pid(dict_t *dict, gf_volfile_t *volfile_obj)
 1640 {
 1641     char *file = NULL;
 1642     int ret = -1;
 1643 
 1644     GF_VALIDATE_OR_GOTO("graph", dict, out);
 1645     GF_VALIDATE_OR_GOTO("graph", volfile_obj, out);
 1646 
 1647     ret = dict_get_str(dict, "pidfile", &file);
 1648     if (ret < 0) {
 1649         gf_msg("mgmt", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
 1650                "Failed to get pidfile from dict for  volfile_id=%s",
 1651                volfile_obj->vol_id);
 1652     }
 1653 
 1654     ret = glusterfs_svc_mux_pidfile_update(volfile_obj, file, getpid());
 1655     if (ret < 0) {
 1656         ret = -1;
 1657         gf_msg("mgmt", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
 1658                "Failed to update "
 1659                "the pidfile for volfile_id=%s",
 1660                volfile_obj->vol_id);
 1661 
 1662         goto out;
 1663     }
 1664 
 1665     if (ret == 1)
 1666         gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED,
 1667                "PID %d updated in pidfile=%s", getpid(), file);
 1668     ret = 0;
 1669 out:
 1670     return ret;
 1671 }
 1672 int
 1673 glusterfs_process_svc_attach_volfp(glusterfs_ctx_t *ctx, FILE *fp,
 1674                                    char *volfile_id, char *checksum,
 1675                                    dict_t *dict)
 1676 {
 1677     glusterfs_graph_t *graph = NULL;
 1678     glusterfs_graph_t *parent_graph = NULL;
 1679     glusterfs_graph_t *clean_graph = NULL;
 1680     int ret = -1;
 1681     xlator_t *xl = NULL;
 1682     xlator_t *last_xl = NULL;
 1683     gf_volfile_t *volfile_obj = NULL;
 1684     pthread_t thread_id = {
 1685         0,
 1686     };
 1687 
 1688     if (!ctx)
 1689         goto out;
 1690     parent_graph = ctx->active;
 1691     graph = glusterfs_graph_construct(fp);
 1692     if (!graph) {
 1693         gf_msg("glusterfsd", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
 1694                "failed to construct the graph");
 1695         goto out;
 1696     }
 1697     graph->parent_down = 0;
 1698     graph->last_xl = glusterfs_get_last_xlator(graph);
 1699 
 1700     for (xl = graph->first; xl; xl = xl->next) {
 1701         if (strcmp(xl->type, "mount/fuse") == 0) {
 1702             gf_msg("glusterfsd", GF_LOG_ERROR, EINVAL,
 1703                    LG_MSG_GRAPH_ATTACH_FAILED,
 1704                    "fuse xlator cannot be specified in volume file");
 1705             goto out;
 1706         }
 1707     }
 1708 
 1709     graph->leaf_count = glusterfs_count_leaves(glusterfs_root(graph));
 1710     xl = graph->first;
 1711     /* TODO memory leaks everywhere need to free graph in case of error */
 1712     if (glusterfs_graph_prepare(graph, ctx, xl->name)) {
 1713         gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
 1714                "failed to prepare graph for xlator %s", xl->name);
 1715         ret = -1;
 1716         goto out;
 1717     } else if (glusterfs_graph_init(graph)) {
 1718         gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
 1719                "failed to initialize graph for xlator %s", xl->name);
 1720         ret = -1;
 1721         goto out;
 1722     } else if (glusterfs_graph_parent_up(graph)) {
 1723         gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
 1724                "failed to link the graphs for xlator %s ", xl->name);
 1725         ret = -1;
 1726         goto out;
 1727     }
 1728 
 1729     if (!parent_graph) {
 1730         parent_graph = glusterfs_muxsvc_setup_parent_graph(ctx, "glustershd",
 1731                                                            "debug/io-stats");
 1732         if (!parent_graph)
 1733             goto out;
 1734         ((xlator_t *)parent_graph->top)->next = xl;
 1735         clean_graph = parent_graph;
 1736     } else {
 1737         last_xl = parent_graph->last_xl;
 1738         if (last_xl)
 1739             last_xl->next = xl;
 1740         xl->prev = last_xl;
 1741     }
 1742     parent_graph->last_xl = graph->last_xl;
 1743 
 1744     ret = glusterfs_xlator_link(parent_graph->top, xl);
 1745     if (ret) {
 1746         gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED,
 1747                "parent up notification failed");
 1748         goto out;
 1749     }
 1750     parent_graph->xl_count += graph->xl_count;
 1751     parent_graph->leaf_count += graph->leaf_count;
 1752     parent_graph->id++;
 1753 
 1754     volfile_obj = GF_CALLOC(1, sizeof(gf_volfile_t), gf_common_volfile_t);
 1755     if (!volfile_obj) {
 1756         ret = -1;
 1757         goto out;
 1758     }
 1759     volfile_obj->pidfp = NULL;
 1760     snprintf(volfile_obj->vol_id, sizeof(volfile_obj->vol_id), "%s",
 1761              volfile_id);
 1762 
 1763     if (strcmp(ctx->cmd_args.process_name, "glustershd") == 0) {
 1764         ret = glusterfs_update_mux_pid(dict, volfile_obj);
 1765         if (ret == -1) {
 1766             GF_FREE(volfile_obj);
 1767             goto out;
 1768         }
 1769     }
 1770 
 1771     graph->used = 1;
 1772     parent_graph->id++;
 1773     list_add(&graph->list, &ctx->graphs);
 1774     INIT_LIST_HEAD(&volfile_obj->volfile_list);
 1775     volfile_obj->graph = graph;
 1776     memcpy(volfile_obj->volfile_checksum, checksum,
 1777            sizeof(volfile_obj->volfile_checksum));
 1778     list_add_tail(&volfile_obj->volfile_list, &ctx->volfile_list);
 1779     gf_log_dump_graph(fp, graph);
 1780     graph = NULL;
 1781 
 1782     ret = 0;
 1783 out:
 1784     if (ret) {
 1785         if (graph) {
 1786             gluster_graph_take_reference(graph->first);
 1787             ret = gf_thread_create_detached(&thread_id, glusterfs_graph_cleanup,
 1788                                             graph, "graph_clean");
 1789             if (ret) {
 1790                 gf_msg("glusterfs", GF_LOG_ERROR, EINVAL,
 1791                        LG_MSG_GRAPH_CLEANUP_FAILED,
 1792                        "%s failed to create clean "
 1793                        "up thread",
 1794                        volfile_id);
 1795                 ret = 0;
 1796             }
 1797         }
 1798         if (clean_graph)
 1799             glusterfs_muxsvc_cleanup_parent(ctx, clean_graph);
 1800     }
 1801     return ret;
 1802 }
 1803 
 1804 int
 1805 glusterfs_mux_volfile_reconfigure(FILE *newvolfile_fp, glusterfs_ctx_t *ctx,
 1806                                   gf_volfile_t *volfile_obj, char *checksum,
 1807                                   dict_t *dict)
 1808 {
 1809     glusterfs_graph_t *oldvolfile_graph = NULL;
 1810     glusterfs_graph_t *newvolfile_graph = NULL;
 1811     char vol_id[NAME_MAX + 1];
 1812 
 1813     int ret = -1;
 1814 
 1815     if (!ctx) {
 1816         gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
 1817                "ctx is NULL");
 1818         goto out;
 1819     }
 1820 
 1821     /* Change the message id */
 1822     if (!volfile_obj) {
 1823         gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
 1824                "failed to get volfile object");
 1825         goto out;
 1826     }
 1827 
 1828     oldvolfile_graph = volfile_obj->graph;
 1829     if (!oldvolfile_graph) {
 1830         goto out;
 1831     }
 1832 
 1833     newvolfile_graph = glusterfs_graph_construct(newvolfile_fp);
 1834 
 1835     if (!newvolfile_graph) {
 1836         goto out;
 1837     }
 1838     newvolfile_graph->last_xl = glusterfs_get_last_xlator(newvolfile_graph);
 1839 
 1840     glusterfs_graph_prepare(newvolfile_graph, ctx, newvolfile_graph->first);
 1841 
 1842     if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) {
 1843         ret = snprintf(vol_id, sizeof(vol_id), "%s", volfile_obj->vol_id);
 1844         if (ret < 0)
 1845             goto out;
 1846         ret = glusterfs_process_svc_detach(ctx, volfile_obj);
 1847         if (ret) {
 1848             gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, EINVAL,
 1849                    LG_MSG_GRAPH_CLEANUP_FAILED,
 1850                    "Could not detach "
 1851                    "old graph. Aborting the reconfiguration operation");
 1852             goto out;
 1853         }
 1854         volfile_obj = NULL;
 1855         ret = glusterfs_process_svc_attach_volfp(ctx, newvolfile_fp, vol_id,
 1856                                                  checksum, dict);
 1857         goto out;
 1858     }
 1859 
 1860     gf_msg_debug("glusterfsd-mgmt", 0,
 1861                  "Only options have changed in the"
 1862                  " new graph");
 1863 
 1864     ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph);
 1865     if (ret) {
 1866         gf_msg_debug("glusterfsd-mgmt", 0,
 1867                      "Could not reconfigure "
 1868                      "new options in old graph");
 1869         goto out;
 1870     }
 1871     memcpy(volfile_obj->volfile_checksum, checksum,
 1872            sizeof(volfile_obj->volfile_checksum));
 1873 
 1874     ret = 0;
 1875 out:
 1876 
 1877     if (newvolfile_graph)
 1878         glusterfs_graph_destroy(newvolfile_graph);
 1879 
 1880     return ret;
 1881 }