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