glusterfs

Форк
0
1934 строки · 52.6 Кб
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
#define xlator_has_parent(xl) (xl->parents != NULL)
39

40
#if 0
41
static void
42
_gf_dump_details (int argc, char **argv)
43
{
44
        extern FILE *gf_log_logfile;
45
        int          i = 0;
46
        char         timestr[GF_TIMESTR_SIZE];
47
        time_t       utime = 0;
48
        pid_t        mypid = 0;
49
        struct utsname uname_buf = {{0, }, };
50
        int            uname_ret = -1;
51

52
        mypid = getpid ();
53
        uname_ret   = uname (&uname_buf);
54

55
        utime = time (NULL);
56
        gf_time_fmt (timestr, sizeof timestr, utime, gf_timefmt_FT);
57
        fprintf (gf_log_logfile,
58
                 "========================================"
59
                 "========================================\n");
60
        fprintf (gf_log_logfile, "Version      : %s %s built on %s %s\n",
61
                 PACKAGE_NAME, PACKAGE_VERSION, __DATE__, __TIME__);
62
        fprintf (gf_log_logfile, "git: %s\n",
63
                 GLUSTERFS_REPOSITORY_REVISION);
64
        fprintf (gf_log_logfile, "Starting Time: %s\n", timestr);
65
        fprintf (gf_log_logfile, "Command line : ");
66
        for (i = 0; i < argc; i++) {
67
                fprintf (gf_log_logfile, "%s ", argv[i]);
68
        }
69

70
        fprintf (gf_log_logfile, "\nPID          : %d\n", mypid);
71

72
        if (uname_ret == 0) {
73
                fprintf (gf_log_logfile, "System name  : %s\n",
74
                         uname_buf.sysname);
75
                fprintf (gf_log_logfile, "Nodename     : %s\n",
76
                         uname_buf.nodename);
77
                fprintf (gf_log_logfile, "Kernel Release : %s\n",
78
                         uname_buf.release);
79
                fprintf (gf_log_logfile, "Hardware Identifier: %s\n",
80
                         uname_buf.machine);
81
        }
82

83

84
        fprintf (gf_log_logfile, "\n");
85
        fflush (gf_log_logfile);
86
}
87
#endif
88

89
int
90
glusterfs_read_secure_access_file(void)
91
{
92
    FILE *fp = NULL;
93
    char line[100] = {
94
        0,
95
    };
96
    int cert_depth = 1; /* Default SSL CERT DEPTH */
97
    regex_t regcmpl;
98
    char *key = {"^option transport.socket.ssl-cert-depth"};
99
    char keyval[50] = {
100
        0,
101
    };
102
    int start = 0, end = 0, copy_len = 0;
103
    regmatch_t result[1] = {{0}};
104

105
    fp = fopen(SECURE_ACCESS_FILE, "r");
106
    if (!fp)
107
        goto out;
108

109
    /* Check if any line matches with key */
110
    while (fgets(line, sizeof(line), fp) != NULL) {
111
        if (regcomp(&regcmpl, key, REG_EXTENDED)) {
112
            goto out;
113
        }
114
        if (!regexec(&regcmpl, line, 1, result, 0)) {
115
            start = result[0].rm_so;
116
            end = result[0].rm_eo;
117
            copy_len = end - start;
118
            gf_strncpy(keyval, line + copy_len, sizeof(keyval));
119
            if (keyval[0]) {
120
                cert_depth = atoi(keyval);
121
                if (cert_depth == 0)
122
                    cert_depth = 1; /* Default SSL CERT DEPTH */
123
                break;
124
            }
125
        }
126
        regfree(&regcmpl);
127
    }
128

129
out:
130
    if (fp)
131
        fclose(fp);
132
    return cert_depth;
133
}
134

135
xlator_t *
136
glusterfs_get_last_xlator(glusterfs_graph_t *graph)
137
{
138
    xlator_t *trav = graph->first;
139
    if (!trav)
140
        return NULL;
141

142
    while (trav->next)
143
        trav = trav->next;
144

145
    return trav;
146
}
147

148
xlator_t *
149
glusterfs_mux_xlator_unlink(xlator_t *pxl, xlator_t *cxl)
150
{
151
    xlator_list_t *unlink = NULL;
152
    xlator_list_t *prev = NULL;
153
    xlator_list_t **tmp = NULL;
154
    xlator_t *next_child = NULL;
155
    xlator_t *xl = NULL;
156

157
    for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next) {
158
        if ((*tmp)->xlator == cxl) {
159
            unlink = *tmp;
160
            *tmp = (*tmp)->next;
161
            if (*tmp)
162
                next_child = (*tmp)->xlator;
163
            break;
164
        }
165
        prev = *tmp;
166
    }
167

168
    if (!prev)
169
        xl = pxl;
170
    else if (prev->xlator)
171
        xl = prev->xlator->graph->last_xl;
172

173
    if (xl)
174
        xl->next = next_child;
175
    if (next_child)
176
        next_child->prev = xl;
177

178
    GF_FREE(unlink);
179
    return next_child;
180
}
181

182
int
183
glusterfs_xlator_link(xlator_t *pxl, xlator_t *cxl)
184
{
185
    xlator_list_t *xlchild = NULL;
186
    xlator_list_t *xlparent = NULL;
187
    xlator_list_t **tmp = NULL;
188

189
    xlparent = (void *)GF_CALLOC(1, sizeof(*xlparent),
190
                                 gf_common_mt_xlator_list_t);
191
    if (!xlparent)
192
        return -1;
193

194
    xlchild = (void *)GF_CALLOC(1, sizeof(*xlchild),
195
                                gf_common_mt_xlator_list_t);
196
    if (!xlchild) {
197
        GF_FREE(xlparent);
198

199
        return -1;
200
    }
201

202
    xlparent->xlator = pxl;
203
    for (tmp = &cxl->parents; *tmp; tmp = &(*tmp)->next)
204
        ;
205
    *tmp = xlparent;
206

207
    xlchild->xlator = cxl;
208
    for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next)
209
        ;
210
    *tmp = xlchild;
211

212
    return 0;
213
}
214

215
void
216
glusterfs_graph_set_first(glusterfs_graph_t *graph, xlator_t *xl)
217
{
218
    xl->next = graph->first;
219
    if (graph->first)
220
        ((xlator_t *)graph->first)->prev = xl;
221
    graph->first = xl;
222

223
    graph->xl_count++;
224
    xl->xl_id = graph->xl_count;
225
}
226

227
int
228
glusterfs_graph_insert(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx,
229
                       const char *type, const char *name,
230
                       gf_boolean_t autoload)
231
{
232
    xlator_t *ixl = NULL;
233

234
    if (!ctx->root) {
235
        gf_msg("glusterfs", GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR,
236
               "volume \"%s\" can be added from command line only "
237
               "on client side",
238
               type);
239

240
        return -1;
241
    }
242

243
    ixl = GF_CALLOC(1, sizeof(*ixl), gf_common_mt_xlator_t);
244
    if (!ixl)
245
        return -1;
246

247
    ixl->ctx = ctx;
248
    ixl->graph = graph;
249
    ixl->options = dict_new();
250
    if (!ixl->options)
251
        goto err;
252

253
    ixl->name = gf_strdup(name);
254
    if (!ixl->name)
255
        goto err;
256

257
    ixl->is_autoloaded = autoload;
258

259
    if (xlator_set_type(ixl, type) == -1) {
260
        gf_msg("glusterfs", GF_LOG_ERROR, 0, LG_MSG_INIT_FAILED,
261
               "%s (%s) initialization failed", name, type);
262
        return -1;
263
    }
264

265
    if (glusterfs_xlator_link(ixl, graph->top) == -1)
266
        goto err;
267
    glusterfs_graph_set_first(graph, ixl);
268
    graph->top = ixl;
269

270
    return 0;
271
err:
272
    xlator_destroy(ixl);
273
    return -1;
274
}
275

276
int
277
glusterfs_graph_acl(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
278
{
279
    int ret = 0;
280
    cmd_args_t *cmd_args = NULL;
281

282
    cmd_args = &ctx->cmd_args;
283

284
    if (!cmd_args->acl)
285
        return 0;
286

287
    ret = glusterfs_graph_insert(graph, ctx, "system/posix-acl",
288
                                 "posix-acl-autoload", 1);
289
    return ret;
290
}
291

292
int
293
glusterfs_graph_worm(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
294
{
295
    int ret = 0;
296
    cmd_args_t *cmd_args = NULL;
297

298
    cmd_args = &ctx->cmd_args;
299

300
    if (!cmd_args->worm)
301
        return 0;
302

303
    ret = glusterfs_graph_insert(graph, ctx, "features/worm", "worm-autoload",
304
                                 1);
305
    return ret;
306
}
307

308
int
309
glusterfs_graph_meta(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
310
{
311
    int ret = 0;
312

313
    if (!ctx->root)
314
        return 0;
315

316
    ret = glusterfs_graph_insert(graph, ctx, "meta", "meta-autoload", 1);
317
    return ret;
318
}
319

320
int
321
glusterfs_graph_mac_compat(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
322
{
323
    int ret = 0;
324
    cmd_args_t *cmd_args = NULL;
325

326
    cmd_args = &ctx->cmd_args;
327

328
    if (cmd_args->mac_compat == GF_OPTION_DISABLE)
329
        return 0;
330

331
    ret = glusterfs_graph_insert(graph, ctx, "features/mac-compat",
332
                                 "mac-compat-autoload", 1);
333

334
    return ret;
335
}
336

337
int
338
glusterfs_graph_gfid_access(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
339
{
340
    int ret = 0;
341
    cmd_args_t *cmd_args = NULL;
342

343
    cmd_args = &ctx->cmd_args;
344

345
    if (!cmd_args->aux_gfid_mount)
346
        return 0;
347

348
    ret = glusterfs_graph_insert(graph, ctx, "features/gfid-access",
349
                                 "gfid-access-autoload", 1);
350
    return ret;
351
}
352

353
static void
354
gf_add_cmdline_options(glusterfs_graph_t *graph, cmd_args_t *cmd_args)
355
{
356
    int ret = 0;
357
    xlator_t *trav = NULL;
358
    xlator_cmdline_option_t *cmd_option = NULL;
359

360
    trav = graph->first;
361

362
    while (trav) {
363
        list_for_each_entry(cmd_option, &cmd_args->xlator_options, cmd_args)
364
        {
365
            if (!fnmatch(cmd_option->volume, trav->name, FNM_NOESCAPE)) {
366
                ret = dict_set_str(trav->options, cmd_option->key,
367
                                   cmd_option->value);
368
                if (ret == 0) {
369
                    gf_msg(trav->name, GF_LOG_TRACE, 0, LG_MSG_VOL_OPTION_ADD,
370
                           "adding option '%s' for "
371
                           "volume '%s' with value '%s'",
372
                           cmd_option->key, trav->name, cmd_option->value);
373
                } else {
374
                    gf_msg(trav->name, GF_LOG_WARNING, -ret,
375
                           LG_MSG_VOL_OPTION_ADD,
376
                           "adding option '%s' for "
377
                           "volume '%s' failed",
378
                           cmd_option->key, trav->name);
379
                }
380
            }
381
        }
382
        trav = trav->next;
383
    }
384
}
385

386
int
387
glusterfs_graph_validate_options(glusterfs_graph_t *graph)
388
{
389
    xlator_t *trav = NULL;
390
    int ret = -1;
391
    char *errstr = NULL;
392

393
    trav = graph->first;
394

395
    while (trav) {
396
        if (list_empty(&trav->volume_options)) {
397
            trav = trav->next;
398
            continue;
399
        }
400

401
        ret = xlator_options_validate(trav, trav->options, &errstr);
402
        if (ret) {
403
            gf_msg(trav->name, GF_LOG_ERROR, 0, LG_MSG_VALIDATION_FAILED,
404
                   "validation failed: "
405
                   "%s",
406
                   errstr);
407
            return ret;
408
        }
409
        trav = trav->next;
410
    }
411

412
    return 0;
413
}
414

415
/* The function is set xl_id , child_count, level
416
   for every xlator after generating a graph.
417
   In case of client graph(like shd,nfs) a single graph
418
   is generated for all the volumes and because of this
419
   huge memory consumption per inode for these graphs.
420
   While a xlator calls inode_table_new it sets the ctxcount
421
   based on the total xlator attached with a graph. In case
422
   of these graphs (shd, nfs) xl_count is huge if high number
423
   of volumes are active in the environment so in case if
424
   100 volumes are exists per inode it will create memory
425
   for 702 ctx (100 * 7 xlators per volume in nfs graph)
426
   and if per ctx memory consumption is 32 bytes per inode
427
   will consume  22464 Bytes that is huge. In case if lru
428
   list is full the consumption will be huge so to reduce memory consumption
429
   the function reset xl_id based on the volume. An inode
430
   can not be associated more than one volume simultaneously
431
   so at the time of get|set ctx on the inode use the parameter
432
   xlator->level, xlator->xl_id to take decision about the index
433
   for specific xlator to save the data on inode
434
*/
435

436
static uint32_t
437
gluster_graph_set_params(xlator_t *xl, uint32_t level, uint32_t id)
438
{
439
    xlator_list_t *list;
440
    uint32_t count;
441

442
    xl->level = level++;
443
    xl->xl_id = id++;
444
    xl->child_count = 0;
445

446
    for (list = xl->children; list != NULL; list = list->next) {
447
        count = gluster_graph_set_params(list->xlator, level, id);
448
        xl->child_count += count;
449
        id += count;
450
    }
451

452
    return xl->child_count + 1;
453
}
454

455
int
456
glusterfs_graph_init(glusterfs_graph_t *graph)
457
{
458
    xlator_t *trav = NULL;
459
    int ret = -1;
460
    xlator_t *top = NULL;
461
    int start = 1;
462

463
    top = graph->top;
464
    /* Always start the level and id to 1, in case of
465
       fuse graph fuse_xlator is not part of the graph
466
       the graph always start from meta-autoload in volfile
467
       so 0th index is reserve for fuse xlator
468
    */
469
    gluster_graph_set_params(top, start, start);
470

471
    trav = graph->first;
472

473
    while (trav) {
474
        ret = xlator_init(trav);
475
        if (ret) {
476
            gf_msg(trav->name, GF_LOG_ERROR, 0, LG_MSG_TRANSLATOR_INIT_FAILED,
477
                   "initializing translator failed");
478
            return ret;
479
        }
480
        trav = trav->next;
481
    }
482

483
    return 0;
484
}
485

486
int
487
glusterfs_graph_deactivate(glusterfs_graph_t *graph)
488
{
489
    xlator_t *top = NULL;
490

491
    if (graph == NULL)
492
        goto out;
493

494
    top = graph->top;
495
    xlator_tree_fini(top);
496
out:
497
    return 0;
498
}
499

500
static int
501
_log_if_unknown_option(dict_t *dict, char *key, data_t *value, void *data)
502
{
503
    volume_option_t *found = NULL;
504
    xlator_t *xl = NULL;
505

506
    xl = data;
507

508
    found = xlator_volume_option_get(xl, key);
509

510
    if (!found) {
511
        gf_msg(xl->name, GF_LOG_DEBUG, 0, LG_MSG_XLATOR_OPTION_INVALID,
512
               "option '%s' is not recognized", key);
513
    }
514

515
    return 0;
516
}
517

518
static void
519
_xlator_check_unknown_options(xlator_t *xl, void *data)
520
{
521
    dict_foreach(xl->options, _log_if_unknown_option, xl);
522
}
523

524
static int
525
glusterfs_graph_unknown_options(glusterfs_graph_t *graph)
526
{
527
    xlator_foreach(graph->first, _xlator_check_unknown_options, NULL);
528
    return 0;
529
}
530

531
static int
532
fill_uuid(char *uuid, int size, struct timeval tv)
533
{
534
    char now_str[GF_TIMESTR_SIZE];
535
    int32_t ret = 0;
536
    gf_time_fmt_tv(now_str, sizeof now_str, &tv, gf_timefmt_dirent);
537
    ret = snprintf(uuid, size, "%s-%d-%s", gf_gethostname(), getpid(), now_str);
538
    if (ret >= size) {
539
        ret = -1;
540
    }
541
    return ret;
542
}
543

544
static int
545
glusterfs_graph_settop(glusterfs_graph_t *graph, char *volume_name,
546
                       gf_boolean_t exact_match)
547
{
548
    int ret = -1;
549
    xlator_t *trav = NULL;
550

551
    if (!volume_name || !exact_match) {
552
        graph->top = graph->first;
553
        ret = 0;
554
    } else {
555
        for (trav = graph->first; trav; trav = trav->next) {
556
            if (strcmp(trav->name, volume_name) == 0) {
557
                graph->top = trav;
558
                ret = 0;
559
                break;
560
            }
561
        }
562
    }
563

564
    return ret;
565
}
566

567
int
568
glusterfs_graph_parent_up(glusterfs_graph_t *graph)
569
{
570
    xlator_t *trav = NULL;
571
    int ret = -1;
572

573
    trav = graph->first;
574

575
    while (trav) {
576
        if (!xlator_has_parent(trav)) {
577
            ret = xlator_notify(trav, GF_EVENT_PARENT_UP, trav);
578
        }
579

580
        if (ret)
581
            break;
582

583
        trav = trav->next;
584
    }
585

586
    return ret;
587
}
588

589
int
590
glusterfs_graph_prepare(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx,
591
                        char *volume_name)
592
{
593
    xlator_t *trav = NULL;
594
    int 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. */
603
    if (!volume_name) {
604
        /* GlusterD does not pass a volume_name */
605
        ret = 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/..."  */
608
        ret = glusterfs_graph_settop(graph, volume_name, _gf_false);
609
    } else if (volume_name[0] == '/') {
610
        /* brick multiplexing passes the brick path */
611
        ret = glusterfs_graph_settop(graph, volume_name, _gf_true);
612
    } else {
613
        ret = glusterfs_graph_settop(graph, volume_name, _gf_false);
614
    }
615

616
    if (ret) {
617
        gf_msg("graph", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_ERROR,
618
               "glusterfs graph settop failed");
619
        errno = EINVAL;
620
        return -1;
621
    }
622

623
    /* XXX: WORM VOLUME */
624
    ret = glusterfs_graph_worm(graph, ctx);
625
    if (ret) {
626
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
627
               "glusterfs graph worm failed");
628
        return -1;
629
    }
630
    ret = glusterfs_graph_acl(graph, ctx);
631
    if (ret) {
632
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
633
               "glusterfs graph ACL failed");
634
        return -1;
635
    }
636

637
    /* XXX: MAC COMPAT */
638
    ret = glusterfs_graph_mac_compat(graph, ctx);
639
    if (ret) {
640
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
641
               "glusterfs graph mac compat failed");
642
        return -1;
643
    }
644

645
    /* XXX: gfid-access */
646
    ret = glusterfs_graph_gfid_access(graph, ctx);
647
    if (ret) {
648
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
649
               "glusterfs graph 'gfid-access' failed");
650
        return -1;
651
    }
652

653
    /* XXX: topmost xlator */
654
    ret = glusterfs_graph_meta(graph, ctx);
655
    if (ret) {
656
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
657
               "glusterfs graph meta failed");
658
        return -1;
659
    }
660

661
    /* XXX: this->ctx setting */
662
    for (trav = graph->first; trav; trav = trav->next) {
663
        trav->ctx = ctx;
664
    }
665

666
    /* XXX: DOB setting */
667
    gettimeofday(&graph->dob, NULL);
668

669
    ret = fill_uuid(graph->graph_uuid, sizeof(graph->graph_uuid), graph->dob);
670
    if (ret < 0) {
671
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR,
672
               "glusterfs fill uuid failed");
673
        return -1;
674
    }
675
    graph->id = ctx->graph_id++;
676

677
    /* XXX: --xlator-option additions */
678
    gf_add_cmdline_options(graph, &ctx->cmd_args);
679

680
    return 0;
681
}
682

683
static xlator_t *
684
glusterfs_root(glusterfs_graph_t *graph)
685
{
686
    return graph->first;
687
}
688

689
static int
690
glusterfs_is_leaf(xlator_t *xl)
691
{
692
    int ret = 0;
693

694
    if (!xl->children)
695
        ret = 1;
696

697
    return ret;
698
}
699

700
static uint32_t
701
glusterfs_count_leaves(xlator_t *xl)
702
{
703
    int n = 0;
704
    xlator_list_t *list = NULL;
705

706
    if (glusterfs_is_leaf(xl))
707
        n = 1;
708
    else
709
        for (list = xl->children; list; list = list->next)
710
            n += glusterfs_count_leaves(list->xlator);
711

712
    return n;
713
}
714

715
int
716
glusterfs_get_leaf_count(glusterfs_graph_t *graph)
717
{
718
    return graph->leaf_count;
719
}
720

721
static int
722
_glusterfs_leaf_position(xlator_t *tgt, int *id, xlator_t *xl)
723
{
724
    xlator_list_t *list = NULL;
725
    int found = 0;
726

727
    if (xl == tgt)
728
        found = 1;
729
    else if (glusterfs_is_leaf(xl))
730
        *id += 1;
731
    else
732
        for (list = xl->children; !found && list; list = list->next)
733
            found = _glusterfs_leaf_position(tgt, id, list->xlator);
734

735
    return found;
736
}
737

738
int
739
glusterfs_leaf_position(xlator_t *tgt)
740
{
741
    xlator_t *root = NULL;
742
    int pos = 0;
743

744
    root = glusterfs_root(tgt->graph);
745

746
    if (!_glusterfs_leaf_position(tgt, &pos, root))
747
        pos = -1;
748

749
    return pos;
750
}
751

752
static int
753
_glusterfs_reachable_leaves(xlator_t *base, xlator_t *xl, dict_t *leaves)
754
{
755
    xlator_list_t *list = NULL;
756
    int err = 1;
757
    int pos = 0;
758
    char *strpos = NULL;
759

760
    if (glusterfs_is_leaf(xl)) {
761
        pos = glusterfs_leaf_position(xl);
762
        if (pos < 0)
763
            goto out;
764

765
        err = gf_asprintf(&strpos, "%d", pos);
766

767
        if (err >= 0) {
768
            err = dict_set_static_ptr(leaves, strpos, base);
769
            GF_FREE(strpos);
770
        }
771
    } else {
772
        for (err = 0, list = xl->children; !err && list; list = list->next)
773
            err = _glusterfs_reachable_leaves(base, list->xlator, leaves);
774
    }
775

776
out:
777
    return 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

792
int
793
glusterfs_reachable_leaves(xlator_t *base, dict_t *leaves)
794
{
795
    xlator_list_t *list = NULL;
796
    int err = 0;
797

798
    for (list = base->children; !err && list; list = list->next)
799
        err = _glusterfs_reachable_leaves(list->xlator, list->xlator, leaves);
800

801
    return err;
802
}
803

804
int
805
glusterfs_graph_activate(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
806
{
807
    int ret = 0;
808
    xlator_t *root = NULL;
809

810
    root = glusterfs_root(graph);
811

812
    graph->leaf_count = glusterfs_count_leaves(root);
813

814
    /* XXX: all xlator options validation */
815
    ret = glusterfs_graph_validate_options(graph);
816
    if (ret) {
817
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_VALIDATION_FAILED,
818
               "validate options failed");
819
        return ret;
820
    }
821

822
    /* XXX: perform init () */
823
    ret = glusterfs_graph_init(graph);
824
    if (ret) {
825
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_INIT_FAILED,
826
               "init failed");
827
        return ret;
828
    }
829

830
    ret = glusterfs_graph_unknown_options(graph);
831
    if (ret) {
832
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_UNKNOWN_OPTIONS_FAILED,
833
               "unknown options "
834
               "failed");
835
        return ret;
836
    }
837

838
    /* XXX: log full graph (_gf_dump_details) */
839

840
    list_add(&graph->list, &ctx->graphs);
841
    ctx->active = graph;
842

843
    /* XXX: attach to root and set active pointer */
844
    if (ctx->root) {
845
        ret = xlator_notify(ctx->root, GF_EVENT_GRAPH_NEW, graph);
846
        if (ret) {
847
            gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED,
848
                   "graph new notification failed");
849
            return ret;
850
        }
851
        ((xlator_t *)ctx->root)->next = graph->top;
852
    }
853

854
    /* XXX: perform parent up */
855
    ret = glusterfs_graph_parent_up(graph);
856
    if (ret) {
857
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED,
858
               "parent up notification failed");
859
        return ret;
860
    }
861

862
    return 0;
863
}
864

865
int
866
xlator_equal_rec(xlator_t *xl1, xlator_t *xl2)
867
{
868
    xlator_list_t *trav1 = NULL;
869
    xlator_list_t *trav2 = NULL;
870
    int ret = 0;
871

872
    if (xl1 == NULL || xl2 == NULL) {
873
        gf_msg_debug("xlator", 0, "invalid argument");
874
        return -1;
875
    }
876

877
    trav1 = xl1->children;
878
    trav2 = xl2->children;
879

880
    while (trav1 && trav2) {
881
        ret = xlator_equal_rec(trav1->xlator, trav2->xlator);
882
        if (ret) {
883
            gf_msg_debug("glusterfsd-mgmt", 0,
884
                         "xlators children "
885
                         "not equal");
886
            goto out;
887
        }
888

889
        trav1 = trav1->next;
890
        trav2 = trav2->next;
891
    }
892

893
    if (trav1 || trav2) {
894
        ret = -1;
895
        goto out;
896
    }
897

898
    if (strcmp(xl1->name, xl2->name)) {
899
        ret = -1;
900
        goto out;
901
    }
902

903
    /* type could have changed even if xlator names match,
904
       e.g cluster/distribute and cluster/nufa share the same
905
       xlator name
906
    */
907
    if (strcmp(xl1->type, xl2->type)) {
908
        ret = -1;
909
        goto out;
910
    }
911
out:
912
    return ret;
913
}
914

915
gf_boolean_t
916
is_graph_topology_equal(glusterfs_graph_t *graph1, glusterfs_graph_t *graph2)
917
{
918
    xlator_t *trav1 = NULL;
919
    xlator_t *trav2 = NULL;
920
    gf_boolean_t ret = _gf_true;
921
    xlator_list_t *ltrav;
922

923
    trav1 = graph1->first;
924
    trav2 = graph2->first;
925

926
    if (strcmp(trav2->type, "protocol/server") == 0) {
927
        trav2 = trav2->children->xlator;
928
        for (ltrav = trav1->children; ltrav; ltrav = ltrav->next) {
929
            trav1 = ltrav->xlator;
930
            if (!trav1->cleanup_starting && !strcmp(trav1->name, trav2->name)) {
931
                break;
932
            }
933
        }
934
        if (!ltrav) {
935
            return _gf_false;
936
        }
937
    }
938

939
    ret = xlator_equal_rec(trav1, trav2);
940

941
    if (ret) {
942
        gf_msg_debug("glusterfsd-mgmt", 0, "graphs are not equal");
943
        ret = _gf_false;
944
        goto out;
945
    }
946

947
    ret = _gf_true;
948
    gf_msg_debug("glusterfsd-mgmt", 0, "graphs are equal");
949

950
out:
951
    return 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
 */
960
int
961
glusterfs_volfile_reconfigure(FILE *newvolfile_fp, glusterfs_ctx_t *ctx)
962
{
963
    glusterfs_graph_t *oldvolfile_graph = NULL;
964
    glusterfs_graph_t *newvolfile_graph = NULL;
965

966
    int ret = -1;
967

968
    if (!ctx) {
969
        gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
970
               "ctx is NULL");
971
        goto out;
972
    }
973

974
    oldvolfile_graph = ctx->active;
975
    if (!oldvolfile_graph) {
976
        ret = 1;
977
        goto out;
978
    }
979

980
    newvolfile_graph = glusterfs_graph_construct(newvolfile_fp);
981

982
    if (!newvolfile_graph) {
983
        goto out;
984
    }
985

986
    glusterfs_graph_prepare(newvolfile_graph, ctx, ctx->cmd_args.volume_name);
987

988
    if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) {
989
        ret = 1;
990
        gf_msg_debug("glusterfsd-mgmt", 0,
991
                     "Graph topology not "
992
                     "equal(should call INIT)");
993
        goto out;
994
    }
995

996
    gf_msg_debug("glusterfsd-mgmt", 0,
997
                 "Only options have changed in the"
998
                 " new graph");
999

1000
    ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph);
1001
    if (ret) {
1002
        gf_msg_debug("glusterfsd-mgmt", 0,
1003
                     "Could not reconfigure "
1004
                     "new options in old graph");
1005
        goto out;
1006
    }
1007

1008
    ret = 0;
1009
out:
1010

1011
    if (newvolfile_graph)
1012
        glusterfs_graph_destroy(newvolfile_graph);
1013

1014
    return ret;
1015
}
1016

1017
/* This function need to remove. This added to support gfapi volfile
1018
 * reconfigure.
1019
 */
1020

1021
int
1022
gf_volfile_reconfigure(int oldvollen, FILE *newvolfile_fp, glusterfs_ctx_t *ctx,
1023
                       const char *oldvolfile)
1024
{
1025
    glusterfs_graph_t *oldvolfile_graph = NULL;
1026
    glusterfs_graph_t *newvolfile_graph = NULL;
1027
    FILE *oldvolfile_fp = NULL;
1028
    /*Since the function mkstemp() replaces XXXXXX,
1029
     * assigning it to a variable
1030
     */
1031
    char temp_file[] = "/tmp/temp_vol_file_XXXXXX";
1032
    gf_boolean_t active_graph_found = _gf_true;
1033

1034
    int ret = -1;
1035
    int u_ret = -1;
1036
    int file_desc = -1;
1037

1038
    if (!oldvollen) {
1039
        ret = 1;  // Has to call INIT for the whole graph
1040
        goto out;
1041
    }
1042

1043
    if (!ctx) {
1044
        gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
1045
               "ctx is NULL");
1046
        goto out;
1047
    }
1048

1049
    oldvolfile_graph = ctx->active;
1050
    if (!oldvolfile_graph) {
1051
        active_graph_found = _gf_false;
1052
        gf_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 */
1056
        file_desc = mkstemp(temp_file);
1057
        if (file_desc < 0) {
1058
            gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, errno,
1059
                   LG_MSG_TMPFILE_CREATE_FAILED,
1060
                   "Unable to "
1061
                   "create temporary volfile");
1062
            goto out;
1063
        }
1064

1065
        /*Calling unlink so that when the file is closed or program
1066
         *terminates the tempfile is deleted.
1067
         */
1068
        u_ret = sys_unlink(temp_file);
1069

1070
        if (u_ret < 0) {
1071
            gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, errno,
1072
                   LG_MSG_TMPFILE_DELETE_FAILED,
1073
                   "Temporary file"
1074
                   " delete failed.");
1075
            sys_close(file_desc);
1076
            goto out;
1077
        }
1078

1079
        oldvolfile_fp = fdopen(file_desc, "w+b");
1080
        if (!oldvolfile_fp)
1081
            goto out;
1082

1083
        fwrite(oldvolfile, oldvollen, 1, oldvolfile_fp);
1084
        fflush(oldvolfile_fp);
1085
        if (ferror(oldvolfile_fp)) {
1086
            goto out;
1087
        }
1088

1089
        oldvolfile_graph = glusterfs_graph_construct(oldvolfile_fp);
1090
        if (!oldvolfile_graph)
1091
            goto out;
1092
    }
1093

1094
    newvolfile_graph = glusterfs_graph_construct(newvolfile_fp);
1095
    if (!newvolfile_graph) {
1096
        goto out;
1097
    }
1098

1099
    glusterfs_graph_prepare(newvolfile_graph, ctx, ctx->cmd_args.volume_name);
1100

1101
    if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) {
1102
        ret = 1;
1103
        gf_msg_debug("glusterfsd-mgmt", 0,
1104
                     "Graph topology not "
1105
                     "equal(should call INIT)");
1106
        goto out;
1107
    }
1108

1109
    gf_msg_debug("glusterfsd-mgmt", 0,
1110
                 "Only options have changed in the"
1111
                 " new graph");
1112

1113
    /* */
1114
    ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph);
1115
    if (ret) {
1116
        gf_msg_debug("glusterfsd-mgmt", 0,
1117
                     "Could not reconfigure "
1118
                     "new options in old graph");
1119
        goto out;
1120
    }
1121

1122
    ret = 0;
1123
out:
1124
    if (oldvolfile_fp)
1125
        fclose(oldvolfile_fp);
1126

1127
    /*  Do not simply destroy the old graph here. If the oldgraph
1128
        is constructed here in this function itself instead of getting
1129
        it from ctx->active (which happens only of ctx->active is NULL),
1130
        then destroy the old graph. If some i/o is still happening in
1131
        the old graph and the old graph is obtained from ctx->active,
1132
        then destroying the graph will cause problems.
1133
    */
1134
    if (!active_graph_found && oldvolfile_graph)
1135
        glusterfs_graph_destroy(oldvolfile_graph);
1136
    if (newvolfile_graph)
1137
        glusterfs_graph_destroy(newvolfile_graph);
1138

1139
    return ret;
1140
}
1141

1142
int
1143
glusterfs_graph_reconfigure(glusterfs_graph_t *oldgraph,
1144
                            glusterfs_graph_t *newgraph)
1145
{
1146
    xlator_t *old_xl = NULL;
1147
    xlator_t *new_xl = NULL;
1148
    xlator_list_t *trav;
1149

1150
    GF_ASSERT(oldgraph);
1151
    GF_ASSERT(newgraph);
1152

1153
    old_xl = oldgraph->first;
1154
    while (old_xl->is_autoloaded) {
1155
        old_xl = old_xl->children->xlator;
1156
    }
1157

1158
    new_xl = newgraph->first;
1159
    while (new_xl->is_autoloaded) {
1160
        new_xl = new_xl->children->xlator;
1161
    }
1162

1163
    if (strcmp(old_xl->type, "protocol/server") != 0) {
1164
        return xlator_tree_reconfigure(old_xl, new_xl);
1165
    }
1166

1167
    /* Some options still need to be handled by the server translator. */
1168
    if (old_xl->reconfigure) {
1169
        old_xl->reconfigure(old_xl, new_xl->options);
1170
    }
1171

1172
    (void)copy_opts_to_child(new_xl, FIRST_CHILD(new_xl), "*auth*");
1173
    new_xl = FIRST_CHILD(new_xl);
1174

1175
    for (trav = old_xl->children; trav; trav = trav->next) {
1176
        if (!trav->xlator->cleanup_starting &&
1177
            !strcmp(trav->xlator->name, new_xl->name)) {
1178
            return xlator_tree_reconfigure(trav->xlator, new_xl);
1179
        }
1180
    }
1181

1182
    return -1;
1183
}
1184

1185
int
1186
glusterfs_graph_destroy_residual(glusterfs_graph_t *graph)
1187
{
1188
    int ret = -1;
1189

1190
    if (graph == NULL)
1191
        return ret;
1192

1193
    ret = xlator_tree_free_memacct(graph->first);
1194

1195
    list_del_init(&graph->list);
1196
    pthread_mutex_destroy(&graph->mutex);
1197
    pthread_cond_destroy(&graph->child_down_cond);
1198
    GF_FREE(graph);
1199

1200
    return 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
 */
1225
int
1226
glusterfs_graph_destroy(glusterfs_graph_t *graph)
1227
{
1228
    int ret = 0;
1229

1230
    GF_VALIDATE_OR_GOTO("graph", graph, out);
1231

1232
    ret = xlator_tree_free_members(graph->first);
1233

1234
    ret = glusterfs_graph_destroy_residual(graph);
1235
out:
1236
    return ret;
1237
}
1238

1239
int
1240
glusterfs_graph_fini(glusterfs_graph_t *graph)
1241
{
1242
    xlator_t *trav = NULL;
1243

1244
    trav = graph->first;
1245

1246
    while (trav) {
1247
        if (trav->init_succeeded) {
1248
            trav->cleanup_starting = 1;
1249
            trav->fini(trav);
1250
            if (trav->local_pool) {
1251
                mem_pool_destroy(trav->local_pool);
1252
                trav->local_pool = NULL;
1253
            }
1254
            if (trav->itable) {
1255
                inode_table_destroy(trav->itable);
1256
                trav->itable = NULL;
1257
            }
1258
            trav->init_succeeded = 0;
1259
        }
1260
        trav = trav->next;
1261
    }
1262

1263
    return 0;
1264
}
1265

1266
int
1267
glusterfs_graph_attach(glusterfs_graph_t *orig_graph, char *path,
1268
                       glusterfs_graph_t **newgraph)
1269
{
1270
    xlator_t *this = THIS;
1271
    FILE *fp;
1272
    glusterfs_graph_t *graph;
1273
    xlator_t *xl;
1274
    char *volfile_id = NULL;
1275
    char *volfile_content = NULL;
1276
    struct stat stbuf = {
1277
        0,
1278
    };
1279
    size_t file_len = -1;
1280
    gf_volfile_t *volfile_obj = NULL;
1281
    int ret = -1;
1282
    char sha256_hash[SHA256_DIGEST_LENGTH] = {
1283
        0,
1284
    };
1285

1286
    if (!orig_graph) {
1287
        return -EINVAL;
1288
    }
1289

1290
    ret = sys_stat(path, &stbuf);
1291
    if (ret < 0) {
1292
        gf_log(THIS->name, GF_LOG_ERROR, "Unable to stat %s (%s)", path,
1293
               strerror(errno));
1294
        return -EINVAL;
1295
    }
1296

1297
    file_len = stbuf.st_size;
1298
    volfile_content = GF_MALLOC(file_len + 1, gf_common_mt_char);
1299
    if (!volfile_content)
1300
        return -ENOMEM;
1301

1302
    fp = fopen(path, "r");
1303
    if (!fp) {
1304
        gf_log(THIS->name, GF_LOG_WARNING, "oops, %s disappeared on us", path);
1305
        GF_FREE(volfile_content);
1306
        return -EIO;
1307
    }
1308

1309
    ret = fread(volfile_content, sizeof(char), file_len, fp);
1310
    if (ret == file_len) {
1311
        glusterfs_compute_sha256((const unsigned char *)volfile_content,
1312
                                 file_len, sha256_hash);
1313
    } else {
1314
        gf_log(THIS->name, GF_LOG_ERROR,
1315
               "read failed on path %s. File size=%" GF_PRI_SIZET
1316
               "read size=%d",
1317
               path, file_len, ret);
1318
        GF_FREE(volfile_content);
1319
        fclose(fp);
1320
        return -EIO;
1321
    }
1322

1323
    GF_FREE(volfile_content);
1324

1325
    graph = glusterfs_graph_construct(fp);
1326
    fclose(fp);
1327
    if (!graph) {
1328
        gf_log(this->name, GF_LOG_WARNING, "could not create graph from %s",
1329
               path);
1330
        return -EIO;
1331
    }
1332

1333
    /*
1334
     * If there's a server translator on top, we want whatever's below
1335
     * that.
1336
     */
1337
    xl = graph->first;
1338
    if (strcmp(xl->type, "protocol/server") == 0) {
1339
        (void)copy_opts_to_child(xl, FIRST_CHILD(xl), "*auth*");
1340
        xl = FIRST_CHILD(xl);
1341
    }
1342
    graph->first = xl;
1343
    *newgraph = graph;
1344

1345
    volfile_id = strstr(path, "/snaps/");
1346
    if (!volfile_id) {
1347
        volfile_id = rindex(path, '/');
1348
        if (volfile_id) {
1349
            ++volfile_id;
1350
        }
1351
    }
1352
    if (volfile_id) {
1353
        xl->volfile_id = gf_strdup(volfile_id);
1354
        /* There's a stray ".vol" at the end. */
1355
        xl->volfile_id[strlen(xl->volfile_id) - 4] = '\0';
1356
    }
1357

1358
    /* TODO memory leaks everywhere need to free graph in case of error */
1359
    if (glusterfs_graph_prepare(graph, this->ctx, xl->name)) {
1360
        gf_log(this->name, GF_LOG_WARNING,
1361
               "failed to prepare graph for xlator %s", xl->name);
1362
        return -EIO;
1363
    } else if (glusterfs_graph_init(graph)) {
1364
        gf_log(this->name, GF_LOG_WARNING,
1365
               "failed to initialize graph for xlator %s", xl->name);
1366
        return -EIO;
1367
    } else if (glusterfs_xlator_link(orig_graph->top, graph->top)) {
1368
        gf_log(this->name, GF_LOG_WARNING,
1369
               "failed to link the graphs for xlator %s ", xl->name);
1370
        return -EIO;
1371
    }
1372

1373
    if (!volfile_obj) {
1374
        volfile_obj = GF_CALLOC(1, sizeof(gf_volfile_t), gf_common_volfile_t);
1375
        if (!volfile_obj) {
1376
            return -EIO;
1377
        }
1378
    }
1379

1380
    INIT_LIST_HEAD(&volfile_obj->volfile_list);
1381
    snprintf(volfile_obj->vol_id, sizeof(volfile_obj->vol_id), "%s",
1382
             xl->volfile_id);
1383
    memcpy(volfile_obj->volfile_checksum, sha256_hash,
1384
           sizeof(volfile_obj->volfile_checksum));
1385
    list_add(&volfile_obj->volfile_list, &this->ctx->volfile_list);
1386

1387
    return 0;
1388
}
1389
int
1390
glusterfs_muxsvc_cleanup_parent(glusterfs_ctx_t *ctx,
1391
                                glusterfs_graph_t *parent_graph)
1392
{
1393
    if (parent_graph) {
1394
        if (parent_graph->first) {
1395
            xlator_destroy(parent_graph->first);
1396
        }
1397
        ctx->active = NULL;
1398
        GF_FREE(parent_graph);
1399
        parent_graph = NULL;
1400
    }
1401
    return 0;
1402
}
1403

1404
void *
1405
glusterfs_graph_cleanup(void *arg)
1406
{
1407
    glusterfs_graph_t *graph = NULL;
1408
    glusterfs_ctx_t *ctx = THIS->ctx;
1409
    int ret = -1;
1410
    graph = arg;
1411

1412
    if (!graph)
1413
        return 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
     */
1423
    if (graph->first)
1424
        default_notify(graph->first, GF_EVENT_PARENT_DOWN, graph->first);
1425

1426
    ret = pthread_mutex_lock(&graph->mutex);
1427
    if (ret != 0) {
1428
        gf_msg("glusterfs", GF_LOG_ERROR, EAGAIN, LG_MSG_GRAPH_CLEANUP_FAILED,
1429
               "Failed to acquire a lock");
1430
        goto out;
1431
    }
1432
    /* check and wait for CHILD_DOWN for top xlator*/
1433
    while (graph->used) {
1434
        ret = pthread_cond_wait(&graph->child_down_cond, &graph->mutex);
1435
        if (ret != 0)
1436
            gf_msg("glusterfs", GF_LOG_INFO, 0, LG_MSG_GRAPH_CLEANUP_FAILED,
1437
                   "cond wait failed ");
1438
    }
1439

1440
    ret = pthread_mutex_unlock(&graph->mutex);
1441
    if (ret != 0) {
1442
        gf_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
     */
1450
    pthread_mutex_lock(&ctx->notify_lock);
1451
    {
1452
        while (ctx->notifying)
1453
            pthread_cond_wait(&ctx->notify_cond, &ctx->notify_lock);
1454
    }
1455
    pthread_mutex_unlock(&ctx->notify_lock);
1456

1457
    pthread_mutex_lock(&ctx->cleanup_lock);
1458
    {
1459
        glusterfs_graph_fini(graph);
1460
        glusterfs_graph_destroy(graph);
1461
    }
1462
    pthread_mutex_unlock(&ctx->cleanup_lock);
1463
out:
1464
    return NULL;
1465
}
1466

1467
glusterfs_graph_t *
1468
glusterfs_muxsvc_setup_parent_graph(glusterfs_ctx_t *ctx, char *name,
1469
                                    char *type)
1470
{
1471
    glusterfs_graph_t *parent_graph = NULL;
1472
    xlator_t *ixl = NULL;
1473
    int ret = -1;
1474
    parent_graph = GF_CALLOC(1, sizeof(*parent_graph),
1475
                             gf_common_mt_glusterfs_graph_t);
1476
    if (!parent_graph)
1477
        goto out;
1478

1479
    INIT_LIST_HEAD(&parent_graph->list);
1480

1481
    ctx->active = parent_graph;
1482
    ixl = GF_CALLOC(1, sizeof(*ixl), gf_common_mt_xlator_t);
1483
    if (!ixl)
1484
        goto out;
1485

1486
    ixl->ctx = ctx;
1487
    ixl->graph = parent_graph;
1488
    ixl->options = dict_new();
1489
    if (!ixl->options)
1490
        goto out;
1491

1492
    ixl->name = gf_strdup(name);
1493
    if (!ixl->name)
1494
        goto out;
1495

1496
    ixl->is_autoloaded = 1;
1497

1498
    if (xlator_set_type(ixl, type) == -1) {
1499
        gf_msg("glusterfs", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
1500
               "%s (%s) set type failed", name, type);
1501
        goto out;
1502
    }
1503

1504
    glusterfs_graph_set_first(parent_graph, ixl);
1505
    parent_graph->top = ixl;
1506
    ixl = NULL;
1507

1508
    gettimeofday(&parent_graph->dob, NULL);
1509
    ret = fill_uuid(parent_graph->graph_uuid, 128, parent_graph->dob);
1510
    if (ret < 0) {
1511
        gf_msg("glusterfs", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
1512
               "%s (%s) fill uuid failed", name, type);
1513
        goto out;
1514
    }
1515
    parent_graph->id = ctx->graph_id++;
1516
    ret = 0;
1517
out:
1518
    if (ixl)
1519
        xlator_destroy(ixl);
1520

1521
    if (ret) {
1522
        glusterfs_muxsvc_cleanup_parent(ctx, parent_graph);
1523
        parent_graph = NULL;
1524
    }
1525
    return parent_graph;
1526
}
1527

1528
int
1529
glusterfs_svc_mux_pidfile_cleanup(gf_volfile_t *volfile_obj)
1530
{
1531
    if (!volfile_obj || !volfile_obj->pidfp)
1532
        return 0;
1533

1534
    gf_msg_trace("glusterfsd", 0, "pidfile %s cleanup", volfile_obj->vol_id);
1535

1536
    lockf(fileno(volfile_obj->pidfp), F_ULOCK, 0);
1537
    fclose(volfile_obj->pidfp);
1538
    volfile_obj->pidfp = NULL;
1539

1540
    return 0;
1541
}
1542

1543
int
1544
glusterfs_process_svc_detach(glusterfs_ctx_t *ctx, gf_volfile_t *volfile_obj)
1545
{
1546
    xlator_t *last_xl = NULL;
1547
    glusterfs_graph_t *graph = NULL;
1548
    glusterfs_graph_t *parent_graph = NULL;
1549
    pthread_t clean_graph = {
1550
        0,
1551
    };
1552
    int ret = -1;
1553
    xlator_t *xl = NULL;
1554

1555
    if (!ctx || !ctx->active || !volfile_obj)
1556
        goto out;
1557

1558
    pthread_mutex_lock(&ctx->cleanup_lock);
1559
    {
1560
        parent_graph = ctx->active;
1561
        graph = volfile_obj->graph;
1562
        if (!graph)
1563
            goto unlock;
1564
        if (graph->first)
1565
            xl = graph->first;
1566

1567
        last_xl = graph->last_xl;
1568
        if (last_xl)
1569
            last_xl->next = NULL;
1570
        if (!xl || xl->cleanup_starting)
1571
            goto unlock;
1572

1573
        xl->cleanup_starting = 1;
1574
        gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_DETACH_STARTED,
1575
               "detaching child %s", volfile_obj->vol_id);
1576

1577
        list_del_init(&volfile_obj->volfile_list);
1578
        glusterfs_mux_xlator_unlink(parent_graph->top, xl);
1579
        glusterfs_svc_mux_pidfile_cleanup(volfile_obj);
1580
        parent_graph->last_xl = glusterfs_get_last_xlator(parent_graph);
1581
        parent_graph->xl_count -= graph->xl_count;
1582
        parent_graph->leaf_count -= graph->leaf_count;
1583
        parent_graph->id++;
1584
        ret = 0;
1585
    }
1586
unlock:
1587
    pthread_mutex_unlock(&ctx->cleanup_lock);
1588
out:
1589
    if (!ret) {
1590
        list_del_init(&volfile_obj->volfile_list);
1591
        if (graph) {
1592
            ret = gf_thread_create_detached(
1593
                &clean_graph, glusterfs_graph_cleanup, graph, "graph_clean");
1594
            if (ret) {
1595
                gf_msg("glusterfs", GF_LOG_ERROR, EINVAL,
1596
                       LG_MSG_GRAPH_CLEANUP_FAILED,
1597
                       "%s failed to create clean "
1598
                       "up thread",
1599
                       volfile_obj->vol_id);
1600
                ret = 0;
1601
            }
1602
        }
1603
        GF_FREE(volfile_obj);
1604
    }
1605
    return ret;
1606
}
1607

1608
int
1609
glusterfs_svc_mux_pidfile_setup(gf_volfile_t *volfile_obj, const char *pid_file)
1610
{
1611
    int ret = -1;
1612
    FILE *pidfp = NULL;
1613

1614
    if (!pid_file || !volfile_obj)
1615
        goto out;
1616

1617
    if (volfile_obj->pidfp) {
1618
        ret = 0;
1619
        goto out;
1620
    }
1621
    pidfp = fopen(pid_file, "a+");
1622
    if (!pidfp) {
1623
        goto out;
1624
    }
1625
    volfile_obj->pidfp = pidfp;
1626

1627
    ret = lockf(fileno(pidfp), F_TLOCK, 0);
1628
    if (ret) {
1629
        ret = 0;
1630
        goto out;
1631
    }
1632
out:
1633
    return ret;
1634
}
1635

1636
int
1637
glusterfs_svc_mux_pidfile_update(gf_volfile_t *volfile_obj,
1638
                                 const char *pid_file, pid_t pid)
1639
{
1640
    int ret = 0;
1641
    FILE *pidfp = NULL;
1642
    int old_pid;
1643

1644
    if (!volfile_obj->pidfp) {
1645
        ret = glusterfs_svc_mux_pidfile_setup(volfile_obj, pid_file);
1646
        if (ret == -1)
1647
            goto out;
1648
    }
1649
    pidfp = volfile_obj->pidfp;
1650
    ret = fscanf(pidfp, "%d", &old_pid);
1651
    if (ret <= 0) {
1652
        goto update;
1653
    }
1654
    if (old_pid == pid) {
1655
        ret = 0;
1656
        goto out;
1657
    } else {
1658
        gf_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",
1661
               old_pid, pid_file, pid);
1662
    }
1663
update:
1664
    ret = sys_ftruncate(fileno(pidfp), 0);
1665
    if (ret) {
1666
        gf_msg("glusterfsd", GF_LOG_ERROR, errno,
1667
               LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED,
1668
               "pidfile %s truncation failed", pid_file);
1669
        goto out;
1670
    }
1671

1672
    ret = fprintf(pidfp, "%d\n", pid);
1673
    if (ret <= 0) {
1674
        gf_msg("glusterfsd", GF_LOG_ERROR, errno,
1675
               LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, "pidfile %s write failed",
1676
               pid_file);
1677
        goto out;
1678
    }
1679

1680
    ret = fflush(pidfp);
1681
    if (ret) {
1682
        gf_msg("glusterfsd", GF_LOG_ERROR, errno,
1683
               LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, "pidfile %s write failed",
1684
               pid_file);
1685
        goto out;
1686
    }
1687
out:
1688
    return ret;
1689
}
1690

1691
int
1692
glusterfs_update_mux_pid(dict_t *dict, gf_volfile_t *volfile_obj)
1693
{
1694
    char *file = NULL;
1695
    int ret = -1;
1696

1697
    GF_VALIDATE_OR_GOTO("graph", dict, out);
1698
    GF_VALIDATE_OR_GOTO("graph", volfile_obj, out);
1699

1700
    ret = dict_get_str(dict, "pidfile", &file);
1701
    if (ret < 0) {
1702
        gf_msg("mgmt", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
1703
               "Failed to get pidfile from dict for  volfile_id=%s",
1704
               volfile_obj->vol_id);
1705
    }
1706

1707
    ret = glusterfs_svc_mux_pidfile_update(volfile_obj, file, getpid());
1708
    if (ret < 0) {
1709
        ret = -1;
1710
        gf_msg("mgmt", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED,
1711
               "Failed to update "
1712
               "the pidfile for volfile_id=%s",
1713
               volfile_obj->vol_id);
1714

1715
        goto out;
1716
    }
1717

1718
    if (ret == 1)
1719
        gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED,
1720
               "PID %d updated in pidfile=%s", getpid(), file);
1721
    ret = 0;
1722
out:
1723
    return ret;
1724
}
1725
int
1726
glusterfs_process_svc_attach_volfp(glusterfs_ctx_t *ctx, FILE *fp,
1727
                                   char *volfile_id, char *checksum,
1728
                                   dict_t *dict)
1729
{
1730
    glusterfs_graph_t *graph = NULL;
1731
    glusterfs_graph_t *parent_graph = NULL;
1732
    glusterfs_graph_t *clean_graph = NULL;
1733
    int ret = -1;
1734
    xlator_t *xl = NULL;
1735
    xlator_t *last_xl = NULL;
1736
    gf_volfile_t *volfile_obj = NULL;
1737
    pthread_t thread_id = {
1738
        0,
1739
    };
1740

1741
    if (!ctx)
1742
        goto out;
1743
    parent_graph = ctx->active;
1744
    graph = glusterfs_graph_construct(fp);
1745
    if (!graph) {
1746
        gf_msg("glusterfsd", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
1747
               "failed to construct the graph");
1748
        goto out;
1749
    }
1750
    graph->parent_down = 0;
1751
    graph->last_xl = glusterfs_get_last_xlator(graph);
1752

1753
    for (xl = graph->first; xl; xl = xl->next) {
1754
        if (strcmp(xl->type, "mount/fuse") == 0) {
1755
            gf_msg("glusterfsd", GF_LOG_ERROR, EINVAL,
1756
                   LG_MSG_GRAPH_ATTACH_FAILED,
1757
                   "fuse xlator cannot be specified in volume file");
1758
            goto out;
1759
        }
1760
    }
1761

1762
    graph->leaf_count = glusterfs_count_leaves(glusterfs_root(graph));
1763
    xl = graph->first;
1764
    /* TODO memory leaks everywhere need to free graph in case of error */
1765
    if (glusterfs_graph_prepare(graph, ctx, xl->name)) {
1766
        gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
1767
               "failed to prepare graph for xlator %s", xl->name);
1768
        ret = -1;
1769
        goto out;
1770
    } else if (glusterfs_graph_init(graph)) {
1771
        gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
1772
               "failed to initialize graph for xlator %s", xl->name);
1773
        ret = -1;
1774
        goto out;
1775
    } else if (glusterfs_graph_parent_up(graph)) {
1776
        gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED,
1777
               "failed to link the graphs for xlator %s ", xl->name);
1778
        ret = -1;
1779
        goto out;
1780
    }
1781

1782
    if (!parent_graph) {
1783
        parent_graph = glusterfs_muxsvc_setup_parent_graph(ctx, "glustershd",
1784
                                                           "debug/io-stats");
1785
        if (!parent_graph)
1786
            goto out;
1787
        ((xlator_t *)parent_graph->top)->next = xl;
1788
        clean_graph = parent_graph;
1789
    } else {
1790
        last_xl = parent_graph->last_xl;
1791
        if (last_xl)
1792
            last_xl->next = xl;
1793
        xl->prev = last_xl;
1794
    }
1795
    parent_graph->last_xl = graph->last_xl;
1796

1797
    ret = glusterfs_xlator_link(parent_graph->top, xl);
1798
    if (ret) {
1799
        gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED,
1800
               "parent up notification failed");
1801
        goto out;
1802
    }
1803
    parent_graph->xl_count += graph->xl_count;
1804
    parent_graph->leaf_count += graph->leaf_count;
1805
    parent_graph->id++;
1806

1807
    volfile_obj = GF_CALLOC(1, sizeof(gf_volfile_t), gf_common_volfile_t);
1808
    if (!volfile_obj) {
1809
        ret = -1;
1810
        goto out;
1811
    }
1812
    volfile_obj->pidfp = NULL;
1813
    snprintf(volfile_obj->vol_id, sizeof(volfile_obj->vol_id), "%s",
1814
             volfile_id);
1815

1816
    if (strcmp(ctx->cmd_args.process_name, "glustershd") == 0) {
1817
        ret = glusterfs_update_mux_pid(dict, volfile_obj);
1818
        if (ret == -1) {
1819
            GF_FREE(volfile_obj);
1820
            goto out;
1821
        }
1822
    }
1823

1824
    graph->used = 1;
1825
    parent_graph->id++;
1826
    list_add(&graph->list, &ctx->graphs);
1827
    INIT_LIST_HEAD(&volfile_obj->volfile_list);
1828
    volfile_obj->graph = graph;
1829
    memcpy(volfile_obj->volfile_checksum, checksum,
1830
           sizeof(volfile_obj->volfile_checksum));
1831
    list_add_tail(&volfile_obj->volfile_list, &ctx->volfile_list);
1832
    gf_log_dump_graph(fp, graph);
1833
    graph = NULL;
1834

1835
    ret = 0;
1836
out:
1837
    if (ret) {
1838
        if (graph) {
1839
            gluster_graph_take_reference(graph->first);
1840
            ret = gf_thread_create_detached(&thread_id, glusterfs_graph_cleanup,
1841
                                            graph, "graph_clean");
1842
            if (ret) {
1843
                gf_msg("glusterfs", GF_LOG_ERROR, EINVAL,
1844
                       LG_MSG_GRAPH_CLEANUP_FAILED,
1845
                       "%s failed to create clean "
1846
                       "up thread",
1847
                       volfile_id);
1848
                ret = 0;
1849
            }
1850
        }
1851
        if (clean_graph)
1852
            glusterfs_muxsvc_cleanup_parent(ctx, clean_graph);
1853
    }
1854
    return ret;
1855
}
1856

1857
int
1858
glusterfs_mux_volfile_reconfigure(FILE *newvolfile_fp, glusterfs_ctx_t *ctx,
1859
                                  gf_volfile_t *volfile_obj, char *checksum,
1860
                                  dict_t *dict)
1861
{
1862
    glusterfs_graph_t *oldvolfile_graph = NULL;
1863
    glusterfs_graph_t *newvolfile_graph = NULL;
1864
    char vol_id[NAME_MAX + 1];
1865

1866
    int ret = -1;
1867

1868
    if (!ctx) {
1869
        gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
1870
               "ctx is NULL");
1871
        goto out;
1872
    }
1873

1874
    /* Change the message id */
1875
    if (!volfile_obj) {
1876
        gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL,
1877
               "failed to get volfile object");
1878
        goto out;
1879
    }
1880

1881
    oldvolfile_graph = volfile_obj->graph;
1882
    if (!oldvolfile_graph) {
1883
        goto out;
1884
    }
1885

1886
    newvolfile_graph = glusterfs_graph_construct(newvolfile_fp);
1887

1888
    if (!newvolfile_graph) {
1889
        goto out;
1890
    }
1891
    newvolfile_graph->last_xl = glusterfs_get_last_xlator(newvolfile_graph);
1892

1893
    glusterfs_graph_prepare(newvolfile_graph, ctx, newvolfile_graph->first);
1894

1895
    if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) {
1896
        ret = snprintf(vol_id, sizeof(vol_id), "%s", volfile_obj->vol_id);
1897
        if (ret < 0)
1898
            goto out;
1899
        ret = glusterfs_process_svc_detach(ctx, volfile_obj);
1900
        if (ret) {
1901
            gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, EINVAL,
1902
                   LG_MSG_GRAPH_CLEANUP_FAILED,
1903
                   "Could not detach "
1904
                   "old graph. Aborting the reconfiguration operation");
1905
            goto out;
1906
        }
1907
        volfile_obj = NULL;
1908
        ret = glusterfs_process_svc_attach_volfp(ctx, newvolfile_fp, vol_id,
1909
                                                 checksum, dict);
1910
        goto out;
1911
    }
1912

1913
    gf_msg_debug("glusterfsd-mgmt", 0,
1914
                 "Only options have changed in the"
1915
                 " new graph");
1916

1917
    ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph);
1918
    if (ret) {
1919
        gf_msg_debug("glusterfsd-mgmt", 0,
1920
                     "Could not reconfigure "
1921
                     "new options in old graph");
1922
        goto out;
1923
    }
1924
    memcpy(volfile_obj->volfile_checksum, checksum,
1925
           sizeof(volfile_obj->volfile_checksum));
1926

1927
    ret = 0;
1928
out:
1929

1930
    if (newvolfile_graph)
1931
        glusterfs_graph_destroy(newvolfile_graph);
1932

1933
    return ret;
1934
}
1935

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.