glusterfs

Форк
0
/
glusterd-snapshot.c 
9479 строк · 300.1 Кб
1
/*
2
   Copyright (c) 2013-2014 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
#include <inttypes.h>
11
#include <sys/types.h>
12
#include <unistd.h>
13
#include <sys/statvfs.h>
14
#include <sys/mount.h>
15
#include <signal.h>
16
#include "glusterd-messages.h"
17
#include "glusterd-errno.h"
18

19
#if defined(GF_LINUX_HOST_OS)
20
#include <mntent.h>
21
#else
22
#include "mntent_compat.h"
23
#endif
24

25
#ifdef __NetBSD__
26
#define umount2(dir, flags) unmount(dir, ((flags) != 0) ? MNT_FORCE : 0)
27
#endif
28

29
#if defined(GF_DARWIN_HOST_OS) || defined(__FreeBSD__)
30
#include <sys/param.h>
31
#include <sys/mount.h>
32
#define umount2(dir, flags) unmount(dir, ((flags) != 0) ? MNT_FORCE : 0)
33
#endif
34

35
#include <regex.h>
36

37
#include <glusterfs/compat.h>
38
#include <glusterfs/logging.h>
39
#include <glusterfs/timer.h>
40
#include "glusterd-mem-types.h"
41
#include "glusterd-sm.h"
42
#include "glusterd-op-sm.h"
43
#include "glusterd-utils.h"
44
#include "glusterd-store.h"
45
#include <glusterfs/run.h>
46
#include "glusterd-volgen.h"
47
#include "glusterd-mgmt.h"
48
#include "glusterd-syncop.h"
49
#include "glusterd-snapshot-utils.h"
50
#include "glusterd-snapd-svc.h"
51

52
#include "glusterfs3.h"
53

54
#include <glusterfs/syscall.h>
55

56
#include <glusterfs/events.h>
57

58
char snap_mount_dir[VALID_GLUSTERD_PATHMAX];
59
struct snap_create_args_ {
60
    xlator_t *this;
61
    dict_t *dict;
62
    dict_t *rsp_dict;
63
    glusterd_volinfo_t *snap_vol;
64
    glusterd_brickinfo_t *brickinfo;
65
    struct syncargs *args;
66
    int32_t volcount;
67
    int32_t brickcount;
68
    int32_t brickorder;
69
};
70

71
/* This structure is used to store unsupported options and their values
72
 * for snapshotted volume.
73
 */
74
struct gd_snap_unsupported_opt_t {
75
    char *key;
76
    char *value;
77
};
78

79
typedef struct snap_create_args_ snap_create_args_t;
80

81
/* Look for disconnected peers, for missed snap creates or deletes */
82
static int32_t
83
glusterd_find_missed_snap(dict_t *rsp_dict, glusterd_volinfo_t *vol,
84
                          struct cds_list_head *peers, int32_t op)
85
{
86
    int32_t brick_count = -1;
87
    int32_t ret = -1;
88
    xlator_t *this = THIS;
89
    glusterd_peerinfo_t *peerinfo = NULL;
90
    glusterd_brickinfo_t *brickinfo = NULL;
91

92
    GF_ASSERT(rsp_dict);
93
    GF_ASSERT(peers);
94
    GF_ASSERT(vol);
95

96
    brick_count = 0;
97
    cds_list_for_each_entry(brickinfo, &vol->bricks, brick_list)
98
    {
99
        if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
100
            /* If the brick belongs to the same node */
101
            brick_count++;
102
            continue;
103
        }
104

105
        RCU_READ_LOCK;
106
        cds_list_for_each_entry_rcu(peerinfo, peers, uuid_list)
107
        {
108
            if (gf_uuid_compare(peerinfo->uuid, brickinfo->uuid)) {
109
                /* If the brick doesn't belong to this peer */
110
                continue;
111
            }
112

113
            /* Found peer who owns the brick,    *
114
             * if peer is not connected or not   *
115
             * friend add it to missed snap list */
116
            if (!(peerinfo->connected) ||
117
                (peerinfo->state != GD_FRIEND_STATE_BEFRIENDED)) {
118
                ret = glusterd_add_missed_snaps_to_dict(
119
                    rsp_dict, vol, brickinfo, brick_count + 1, op);
120
                if (ret) {
121
                    RCU_READ_UNLOCK;
122
                    gf_msg(this->name, GF_LOG_ERROR, 0,
123
                           GD_MSG_MISSED_SNAP_CREATE_FAIL,
124
                           "Failed to add missed snapshot "
125
                           "info for %s:%s in the "
126
                           "rsp_dict",
127
                           brickinfo->hostname, brickinfo->path);
128
                    goto out;
129
                }
130
            }
131
        }
132
        RCU_READ_UNLOCK;
133
        brick_count++;
134
    }
135

136
    ret = 0;
137
out:
138
    gf_msg_trace(this->name, 0, "Returning %d", ret);
139
    return ret;
140
}
141

142
int
143
snap_max_limits_display_commit(dict_t *rsp_dict, char *volname, char *op_errstr,
144
                               int len)
145
{
146
    char err_str[PATH_MAX] = "";
147
    char key[64] = "";
148
    int keylen;
149
    glusterd_conf_t *conf = NULL;
150
    glusterd_volinfo_t *volinfo = NULL;
151
    int ret = -1;
152
    uint64_t active_hard_limit = 0;
153
    uint64_t snap_max_limit = 0;
154
    uint64_t soft_limit_value = -1;
155
    uint64_t count = 0;
156
    xlator_t *this = THIS;
157
    uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
158
    uint64_t opt_soft_max = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT;
159
    char *auto_delete = "disable";
160
    char *snap_activate = "disable";
161

162
    GF_ASSERT(rsp_dict);
163
    GF_ASSERT(op_errstr);
164

165
    conf = this->private;
166

167
    GF_ASSERT(conf);
168

169
    /* config values snap-max-hard-limit and snap-max-soft-limit are
170
     * optional and hence we are not erroring out if values are not
171
     * present
172
     */
173
    gd_get_snap_conf_values_if_present(conf->opts, &opt_hard_max,
174
                                       &opt_soft_max);
175

176
    if (!volname) {
177
        /* For system limit */
178
        cds_list_for_each_entry(volinfo, &conf->volumes, vol_list)
179
        {
180
            if (volinfo->is_snap_volume == _gf_true)
181
                continue;
182

183
            snap_max_limit = volinfo->snap_max_hard_limit;
184
            if (snap_max_limit > opt_hard_max)
185
                active_hard_limit = opt_hard_max;
186
            else
187
                active_hard_limit = snap_max_limit;
188

189
            soft_limit_value = (opt_soft_max * active_hard_limit) / 100;
190

191
            keylen = snprintf(key, sizeof(key), "volume%" PRId64 "-volname",
192
                              count);
193
            ret = dict_set_strn(rsp_dict, key, keylen, volinfo->volname);
194
            if (ret) {
195
                len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
196
                if (len < 0) {
197
                    strcpy(err_str, "<error>");
198
                }
199
                goto out;
200
            }
201

202
            snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-hard-limit",
203
                     count);
204
            ret = dict_set_uint64(rsp_dict, key, snap_max_limit);
205
            if (ret) {
206
                len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
207
                if (len < 0) {
208
                    strcpy(err_str, "<error>");
209
                }
210
                goto out;
211
            }
212

213
            snprintf(key, sizeof(key), "volume%" PRId64 "-active-hard-limit",
214
                     count);
215
            ret = dict_set_uint64(rsp_dict, key, active_hard_limit);
216
            if (ret) {
217
                len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
218
                if (len < 0) {
219
                    strcpy(err_str, "<error>");
220
                }
221
                goto out;
222
            }
223

224
            snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-soft-limit",
225
                     count);
226
            ret = dict_set_uint64(rsp_dict, key, soft_limit_value);
227
            if (ret) {
228
                len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
229
                if (len < 0) {
230
                    strcpy(err_str, "<error>");
231
                }
232
                goto out;
233
            }
234
            count++;
235
        }
236

237
        ret = dict_set_uint64(rsp_dict, "voldisplaycount", count);
238
        if (ret) {
239
            snprintf(err_str, PATH_MAX, "Failed to set voldisplaycount");
240
            goto out;
241
        }
242
    } else {
243
        /*  For one volume */
244
        ret = glusterd_volinfo_find(volname, &volinfo);
245
        if (ret) {
246
            snprintf(err_str, PATH_MAX,
247
                     "Volume (%s) does not "
248
                     "exist",
249
                     volname);
250
            goto out;
251
        }
252

253
        snap_max_limit = volinfo->snap_max_hard_limit;
254
        if (snap_max_limit > opt_hard_max)
255
            active_hard_limit = opt_hard_max;
256
        else
257
            active_hard_limit = snap_max_limit;
258

259
        soft_limit_value = (opt_soft_max * active_hard_limit) / 100;
260

261
        keylen = snprintf(key, sizeof(key), "volume%" PRId64 "-volname", count);
262
        ret = dict_set_strn(rsp_dict, key, keylen, volinfo->volname);
263
        if (ret) {
264
            len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
265
            if (len < 0) {
266
                strcpy(err_str, "<error>");
267
            }
268
            goto out;
269
        }
270

271
        snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-hard-limit",
272
                 count);
273
        ret = dict_set_uint64(rsp_dict, key, snap_max_limit);
274
        if (ret) {
275
            len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
276
            if (len < 0) {
277
                strcpy(err_str, "<error>");
278
            }
279
            goto out;
280
        }
281

282
        snprintf(key, sizeof(key), "volume%" PRId64 "-active-hard-limit",
283
                 count);
284
        ret = dict_set_uint64(rsp_dict, key, active_hard_limit);
285
        if (ret) {
286
            len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
287
            if (len < 0) {
288
                strcpy(err_str, "<error>");
289
            }
290
            goto out;
291
        }
292

293
        snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-soft-limit",
294
                 count);
295
        ret = dict_set_uint64(rsp_dict, key, soft_limit_value);
296
        if (ret) {
297
            len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
298
            if (len < 0) {
299
                strcpy(err_str, "<error>");
300
            }
301
            goto out;
302
        }
303

304
        count++;
305

306
        ret = dict_set_uint64(rsp_dict, "voldisplaycount", count);
307
        if (ret) {
308
            snprintf(err_str, PATH_MAX, "Failed to set voldisplaycount");
309
            goto out;
310
        }
311
    }
312

313
    ret = dict_set_uint64(rsp_dict, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
314
                          opt_hard_max);
315
    if (ret) {
316
        snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
317
                 GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
318
        goto out;
319
    }
320

321
    ret = dict_set_uint64(rsp_dict, GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT,
322
                          opt_soft_max);
323
    if (ret) {
324
        snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
325
                 GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT);
326
        goto out;
327
    }
328

329
    /* "auto-delete" might not be set by user explicitly,
330
     * in that case it's better to consider the default value.
331
     * Hence not erroring out if Key is not found.
332
     */
333
    ret = dict_get_str(conf->opts, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE,
334
                       &auto_delete);
335

336
    ret = dict_set_dynstr_with_alloc(
337
        rsp_dict, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, auto_delete);
338
    if (ret) {
339
        snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
340
                 GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE);
341
        goto out;
342
    }
343

344
    /* "snap-activate-on-create" might not be set by user explicitly,
345
     * in that case it's better to consider the default value.
346
     * Hence not erroring out if Key is not found.
347
     */
348
    ret = dict_get_str(conf->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE,
349
                       &snap_activate);
350

351
    ret = dict_set_dynstr_with_alloc(rsp_dict, GLUSTERD_STORE_KEY_SNAP_ACTIVATE,
352
                                     snap_activate);
353
    if (ret) {
354
        snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
355
                 GLUSTERD_STORE_KEY_SNAP_ACTIVATE);
356
        goto out;
357
    }
358

359
    ret = 0;
360
out:
361
    if (ret) {
362
        strncpy(op_errstr, err_str, len);
363
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "%s",
364
               err_str);
365
    }
366
    return ret;
367
}
368

369
/* Third argument of scandir(used in glusterd_copy_geo_rep_session_files)
370
 * is filter function. As we don't want "." and ".." files present in the
371
 * directory, we are excliding these 2 files.
372
 * "file_select" function here does the job of filtering.
373
 */
374
int
375
file_select(const struct dirent *entry)
376
{
377
    if (entry == NULL)
378
        return (FALSE);
379

380
    if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
381
        return (FALSE);
382
    else
383
        return (TRUE);
384
}
385

386
int32_t
387
glusterd_copy_geo_rep_session_files(char *session, glusterd_volinfo_t *snap_vol)
388
{
389
    int32_t ret = -1;
390
    char snap_session_dir[PATH_MAX] = "";
391
    char georep_session_dir[PATH_MAX] = "";
392
    regex_t reg_exp;
393
    int file_count = -1;
394
    struct dirent **files = {
395
        0,
396
    };
397
    xlator_t *this = THIS;
398
    int i = 0;
399
    char src_path[PATH_MAX] = "";
400
    char dest_path[PATH_MAX] = "";
401
    glusterd_conf_t *priv = NULL;
402

403
    priv = this->private;
404
    GF_ASSERT(priv);
405

406
    GF_ASSERT(session);
407
    GF_ASSERT(snap_vol);
408

409
    ret = snprintf(georep_session_dir, sizeof(georep_session_dir), "%s/%s/%s",
410
                   priv->workdir, GEOREP, session);
411
    if (ret < 0) { /* Negative value is an error */
412
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
413
        goto out;
414
    }
415

416
    ret = snprintf(snap_session_dir, sizeof(snap_session_dir), "%s/%s/%s/%s/%s",
417
                   priv->workdir, GLUSTERD_VOL_SNAP_DIR_PREFIX,
418
                   snap_vol->snapshot->snapname, GEOREP, session);
419
    if (ret < 0) { /* Negative value is an error */
420
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
421
        goto out;
422
    }
423

424
    ret = mkdir_p(snap_session_dir, 0755, _gf_true);
425
    if (ret) {
426
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
427
               "Creating directory %s failed", snap_session_dir);
428
        goto out;
429
    }
430

431
    ret = regcomp(&reg_exp, "(.*status$)|(.*conf$)\0", REG_EXTENDED);
432
    if (ret) {
433
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REG_COMPILE_FAILED,
434
               "Failed to compile the regular expression");
435
        goto out;
436
    }
437

438
    /* If there are no files in a particular session then fail it*/
439
    file_count = scandir(georep_session_dir, &files, file_select, alphasort);
440
    if (file_count <= 0) {
441
        ret = -1;
442
        gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
443
               "Session files not present "
444
               "in %s",
445
               georep_session_dir);
446
        goto out_reg_exp;
447
    }
448

449
    /* Now compare the file name with regular expression to see if
450
     * there is a match
451
     */
452
    for (i = 0; i < file_count; i++) {
453
        if (regexec(&reg_exp, files[i]->d_name, 0, NULL, 0))
454
            continue;
455

456
        ret = snprintf(src_path, sizeof(src_path), "%s/%s", georep_session_dir,
457
                       files[i]->d_name);
458
        if (ret < 0) {
459
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
460
            goto out_reg_exp;
461
        }
462

463
        ret = snprintf(dest_path, sizeof(dest_path), "%s/%s", snap_session_dir,
464
                       files[i]->d_name);
465
        if (ret < 0) {
466
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
467
            goto out_reg_exp;
468
        }
469

470
        ret = glusterd_copy_file(src_path, dest_path);
471
        if (ret) {
472
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
473
                   "Could not copy file %s of session %s", files[i]->d_name,
474
                   session);
475
            goto out_reg_exp;
476
        }
477
    }
478

479
out_reg_exp:
480
    regfree(&reg_exp);
481

482
out:
483
    /* files are malloc'd by scandir, free them */
484
    if (file_count > 0) {
485
        while (file_count--) {
486
            free(files[file_count]);
487
        }
488
        free(files);
489
    }
490
    return ret;
491
}
492

493
/* This function will take backup of the volume store
494
 * of the to-be restored volume. This will help us to
495
 * revert the operation if it fails.
496
 *
497
 * @param volinfo volinfo of the origin volume
498
 *
499
 * @return 0 on success and -1 on failure
500
 */
501
int
502
glusterd_snapshot_backup_vol(glusterd_volinfo_t *volinfo)
503
{
504
    char pathname[PATH_MAX] = "";
505
    int ret = -1;
506
    int op_ret = 0;
507
    char delete_path[PATH_MAX] = "";
508
    char trashdir[PATH_MAX] = "";
509
    glusterd_conf_t *priv = NULL;
510
    xlator_t *this = THIS;
511
    int32_t len = 0;
512

513
    priv = this->private;
514
    GF_ASSERT(priv);
515
    GF_ASSERT(volinfo);
516

517
    GLUSTERD_GET_VOLUME_DIR(pathname, volinfo, priv);
518

519
    len = snprintf(delete_path, sizeof(delete_path),
520
                   "%s/" GLUSTERD_TRASH "/vols-%s.deleted", priv->workdir,
521
                   volinfo->volname);
522
    if ((len < 0) || (len >= sizeof(delete_path))) {
523
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
524
        goto out;
525
    }
526

527
    len = snprintf(trashdir, sizeof(trashdir), "%s/" GLUSTERD_TRASH,
528
                   priv->workdir);
529
    if ((len < 0) || (len >= sizeof(trashdir))) {
530
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
531
        goto out;
532
    }
533

534
    /* Create trash folder if it is not there */
535
    ret = sys_mkdir(trashdir, 0755);
536
    if (ret && errno != EEXIST) {
537
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
538
               "Failed to create trash directory, reason : %s",
539
               strerror(errno));
540
        ret = -1;
541
        goto out;
542
    }
543

544
    /* Move the origin volume volder to the backup location */
545
    ret = sys_rename(pathname, delete_path);
546
    if (ret) {
547
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED,
548
               "Failed to rename snap "
549
               "directory %s to %s",
550
               pathname, delete_path);
551
        goto out;
552
    }
553

554
    /* Re-create an empty origin volume folder so that restore can
555
     * happen. */
556
    ret = sys_mkdir(pathname, 0755);
557
    if (ret && errno != EEXIST) {
558
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
559
               "Failed to create origin "
560
               "volume directory (%s), reason : %s",
561
               pathname, strerror(errno));
562
        ret = -1;
563
        goto out;
564
    }
565

566
    ret = 0;
567
out:
568
    /* Save the actual return value */
569
    op_ret = ret;
570
    if (ret) {
571
        /* Revert the changes in case of failure */
572
        ret = sys_rmdir(pathname);
573
        if (ret) {
574
            gf_msg_debug(this->name, errno, "Failed to rmdir: %s", pathname);
575
        }
576

577
        ret = sys_rename(delete_path, pathname);
578
        if (ret) {
579
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED,
580
                   "Failed to rename directory %s to %s", delete_path,
581
                   pathname);
582
        }
583

584
        ret = sys_rmdir(trashdir);
585
        if (ret) {
586
            gf_msg_debug(this->name, errno, "Failed to rmdir: %s", trashdir);
587
        }
588
    }
589

590
    gf_msg_trace(this->name, 0, "Returning %d", op_ret);
591

592
    return op_ret;
593
}
594

595
static int32_t
596
glusterd_copy_geo_rep_files(glusterd_volinfo_t *origin_vol,
597
                            glusterd_volinfo_t *snap_vol, dict_t *rsp_dict)
598
{
599
    int32_t ret = -1;
600
    int i = 0;
601
    xlator_t *this = THIS;
602
    char key[32] = "";
603
    char session[PATH_MAX] = "";
604
    char secondary[PATH_MAX] = "";
605
    char snapgeo_dir[PATH_MAX] = "";
606
    glusterd_conf_t *priv = NULL;
607

608
    priv = this->private;
609
    GF_ASSERT(priv);
610

611
    GF_ASSERT(origin_vol);
612
    GF_ASSERT(snap_vol);
613
    GF_ASSERT(rsp_dict);
614

615
    /* This condition is not satisfied if the volume
616
     * is secondary volume.
617
     */
618
    if (!origin_vol->gsync_secondaries) {
619
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_SECONDARY,
620
                NULL);
621
        ret = 0;
622
        goto out;
623
    }
624

625
    GLUSTERD_GET_SNAP_GEO_REP_DIR(snapgeo_dir, snap_vol->snapshot, priv);
626

627
    ret = sys_mkdir(snapgeo_dir, 0755);
628
    if (ret) {
629
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
630
               "Creating directory %s failed", snapgeo_dir);
631
        goto out;
632
    }
633

634
    for (i = 1; i <= origin_vol->gsync_secondaries->count; i++) {
635
        ret = snprintf(key, sizeof(key), "secondary%d", i);
636
        if (ret < 0) /* Negative value is an error */
637
            goto out;
638

639
        ret = glusterd_get_geo_rep_session(key, origin_vol->volname,
640
                                           origin_vol->gsync_secondaries,
641
                                           session, secondary);
642
        if (ret) {
643
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GEOREP_GET_FAILED,
644
                   "Failed to get geo-rep session");
645
            goto out;
646
        }
647

648
        ret = glusterd_copy_geo_rep_session_files(session, snap_vol);
649
        if (ret) {
650
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED,
651
                   "Failed to copy files"
652
                   " related to session %s",
653
                   session);
654
            goto out;
655
        }
656
    }
657

658
out:
659
    return ret;
660
}
661

662
/* This function will restore a snapshot volumes
663
 *
664
 * @param dict          dictionary containing snapshot restore request
665
 * @param op_errstr     In case of any failure error message will be returned
666
 *                      in this variable
667
 * @return              Negative value on Failure and 0 in success
668
 */
669
int
670
glusterd_snapshot_restore(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
671
{
672
    int ret = -1;
673
    int32_t volcount = -1;
674
    char *snapname = NULL;
675
    xlator_t *this = THIS;
676
    glusterd_volinfo_t *snap_volinfo = NULL;
677
    glusterd_volinfo_t *tmp = NULL;
678
    glusterd_volinfo_t *parent_volinfo = NULL;
679
    glusterd_snap_t *snap = NULL;
680
    glusterd_conf_t *priv = NULL;
681
    gf_boolean_t retain_origin_path = _gf_false;
682

683
    GF_ASSERT(dict);
684
    GF_ASSERT(op_errstr);
685
    GF_ASSERT(rsp_dict);
686

687
    priv = this->private;
688
    GF_ASSERT(priv);
689

690
    ret = dict_get_str(dict, "snapname", &snapname);
691
    if (ret) {
692
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
693
               "Failed to get snap name");
694
        goto out;
695
    }
696

697
    snap = glusterd_find_snap_by_name(snapname);
698
    if (NULL == snap) {
699
        ret = gf_asprintf(op_errstr, "Snapshot (%s) does not exist", snapname);
700
        if (ret < 0) {
701
            goto out;
702
        }
703
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND, "%s",
704
               *op_errstr);
705
        ret = -1;
706
        goto out;
707
    }
708

709
    volcount = 0;
710
    cds_list_for_each_entry_safe(snap_volinfo, tmp, &snap->volumes, vol_list)
711
    {
712
        volcount++;
713
        ret = glusterd_volinfo_find(snap_volinfo->parent_volname,
714
                                    &parent_volinfo);
715
        if (ret) {
716
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
717
                   "Could not get volinfo of %s", snap_volinfo->parent_volname);
718
            goto out;
719
        }
720

721
        ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
722
                                         uuid_utoa(snap->snap_id));
723
        if (ret) {
724
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
725
                   "Failed to set snap "
726
                   "uuid in response dictionary for %s snapshot",
727
                   snap->snapname);
728
            goto out;
729
        }
730

731
        ret = dict_set_dynstr_with_alloc(rsp_dict, "volname",
732
                                         snap_volinfo->parent_volname);
733
        if (ret) {
734
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
735
                   "Failed to set snap "
736
                   "uuid in response dictionary for %s snapshot",
737
                   snap->snapname);
738
            goto out;
739
        }
740

741
        ret = dict_set_dynstr_with_alloc(rsp_dict, "volid",
742
                                         uuid_utoa(parent_volinfo->volume_id));
743
        if (ret) {
744
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
745
                   "Failed to set snap "
746
                   "uuid in response dictionary for %s snapshot",
747
                   snap->snapname);
748
            goto out;
749
        }
750

751
        if (is_origin_glusterd(dict) == _gf_true) {
752
            /* From origin glusterd check if      *
753
             * any peers with snap bricks is down */
754
            ret = glusterd_find_missed_snap(rsp_dict, snap_volinfo,
755
                                            &priv->peers,
756
                                            GF_SNAP_OPTION_TYPE_RESTORE);
757
            if (ret) {
758
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_GET_FAIL,
759
                       "Failed to find missed snap restores");
760
                goto out;
761
            }
762
        }
763

764
        /* During snapshot restore, mount point for stopped snap
765
         * should exist as it is required to set extended attribute.
766
         */
767
        ret = glusterd_recreate_vol_brick_mounts(this, snap_volinfo);
768
        if (ret) {
769
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRK_MNT_RECREATE_FAIL,
770
                   "Failed to recreate brick mounts for %s", snap->snapname);
771
            goto out;
772
        }
773

774
        /* Call restore command for each bricks */
775
        ret = glusterd_bricks_snapshot_restore(rsp_dict, snap_volinfo,
776
                                               &retain_origin_path);
777
        if (ret) {
778
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
779
                   "Failed to restore snap");
780
            goto out;
781
        }
782

783
        ret = gd_restore_snap_volume(dict, rsp_dict, parent_volinfo,
784
                                     snap_volinfo, volcount,
785
                                     retain_origin_path);
786
        if (ret) {
787
            /* No need to update op_errstr because it is assumed
788
             * that the called function will do that in case of
789
             * failure.
790
             */
791
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
792
                   "Failed to restore "
793
                   "snap for %s",
794
                   snapname);
795
            goto out;
796
        }
797

798
        /* Detach the volinfo from priv->volumes, so that no new
799
         * command can ref it any more and then unref it.
800
         */
801
        cds_list_del_init(&parent_volinfo->vol_list);
802
        glusterd_volinfo_unref(parent_volinfo);
803
    }
804

805
    ret = 0;
806

807
    /* TODO: Need to check if we need to delete the snap after the
808
     * operation is successful or not. Also need to persist the state
809
     * of restore operation in the store.
810
     */
811
out:
812
    return ret;
813
}
814

815
/* This function is called before actual restore is taken place. This function
816
 * will validate whether the snapshot volumes are ready to be restored or not.
817
 *
818
 * @param dict          dictionary containing snapshot restore request
819
 * @param op_errstr     In case of any failure error message will be returned
820
 *                      in this variable
821
 * @param rsp_dict      response dictionary
822
 * @return              Negative value on Failure and 0 in success
823
 */
824
int32_t
825
glusterd_snapshot_restore_prevalidate(dict_t *dict, char **op_errstr,
826
                                      uint32_t *op_errno, dict_t *rsp_dict)
827
{
828
    int ret = -1;
829
    int32_t i = 0;
830
    int32_t volcount = 0;
831
    int32_t brick_count = 0;
832
    gf_boolean_t snap_restored = _gf_false;
833
    char key[64] = "";
834
    int keylen;
835
    char *volname = NULL;
836
    char *snapname = NULL;
837
    glusterd_volinfo_t *volinfo = NULL;
838
    glusterd_brickinfo_t *brickinfo = NULL;
839
    glusterd_snap_t *snap = NULL;
840
    xlator_t *this = THIS;
841

842
    GF_ASSERT(dict);
843
    GF_ASSERT(op_errstr);
844
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
845
    GF_ASSERT(rsp_dict);
846

847
    ret = dict_get_str(dict, "snapname", &snapname);
848
    if (ret) {
849
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
850
               "Failed to get "
851
               "snap name");
852
        goto out;
853
    }
854

855
    snap = glusterd_find_snap_by_name(snapname);
856
    if (NULL == snap) {
857
        ret = gf_asprintf(op_errstr, "Snapshot (%s) does not exist", snapname);
858
        *op_errno = EG_SNAPEXST;
859
        if (ret < 0) {
860
            goto out;
861
        }
862
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND, "%s",
863
               *op_errstr);
864
        ret = -1;
865
        goto out;
866
    }
867

868
    snap_restored = snap->snap_restored;
869

870
    if (snap_restored) {
871
        ret = gf_asprintf(op_errstr,
872
                          "Snapshot (%s) is already "
873
                          "restored",
874
                          snapname);
875
        if (ret < 0) {
876
            goto out;
877
        }
878
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
879
               *op_errstr);
880
        ret = -1;
881
        goto out;
882
    }
883

884
    ret = dict_set_str_sizen(rsp_dict, "snapname", snapname);
885
    if (ret) {
886
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
887
               "Failed to set "
888
               "snap name(%s)",
889
               snapname);
890
        goto out;
891
    }
892

893
    ret = dict_get_int32(dict, "volcount", &volcount);
894

895
    if (ret) {
896
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
897
               "Failed to get volume count");
898
        goto out;
899
    }
900

901
    /* Snapshot restore will only work if all the volumes,
902
       that are part of the snapshot, are stopped. */
903
    for (i = 1; i <= volcount; ++i) {
904
        keylen = snprintf(key, sizeof(key), "volname%d", i);
905
        ret = dict_get_strn(dict, key, keylen, &volname);
906
        if (ret) {
907
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
908
                   "Failed to "
909
                   "get volume name");
910
            goto out;
911
        }
912

913
        ret = glusterd_volinfo_find(volname, &volinfo);
914
        if (ret) {
915
            ret = gf_asprintf(op_errstr,
916
                              "Volume (%s) "
917
                              "does not exist",
918
                              volname);
919
            *op_errno = EG_NOVOL;
920
            if (ret < 0) {
921
                goto out;
922
            }
923
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND, "%s",
924
                   *op_errstr);
925
            ret = -1;
926
            goto out;
927
        }
928

929
        if (glusterd_is_volume_started(volinfo)) {
930
            ret = gf_asprintf(
931
                op_errstr,
932
                "Volume (%s) has been "
933
                "started. Volume needs to be stopped before restoring "
934
                "a snapshot.",
935
                volname);
936
            *op_errno = EG_VOLRUN;
937
            if (ret < 0) {
938
                goto out;
939
            }
940
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
941
                   *op_errstr);
942
            ret = -1;
943
            goto out;
944
        }
945

946
        /* Take backup of the volinfo folder */
947
        ret = glusterd_snapshot_backup_vol(volinfo);
948
        if (ret) {
949
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
950
                   "Failed to backup "
951
                   "volume backend files for %s volume",
952
                   volinfo->volname);
953
            goto out;
954
        }
955
    }
956

957
    /* Get brickinfo for snap_volumes */
958
    volcount = 0;
959
    cds_list_for_each_entry(volinfo, &snap->volumes, vol_list)
960
    {
961
        volcount++;
962
        brick_count = 0;
963

964
        cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
965
        {
966
            brick_count++;
967
            if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
968
                continue;
969

970
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.path", volcount,
971
                              brick_count);
972
            ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->path);
973
            if (ret) {
974
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
975
                       "Failed to set %s", key);
976
                goto out;
977
            }
978

979
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.origin_path",
980
                              volcount, brick_count);
981
            ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->origin_path);
982
            if (ret) {
983
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
984
                       "Failed to set %s", key);
985
                goto out;
986
            }
987

988
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.snap_status",
989
                              volcount, brick_count);
990
            ret = dict_set_int32n(rsp_dict, key, keylen,
991
                                  brickinfo->snap_status);
992
            if (ret) {
993
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
994
                       "Failed to set %s", key);
995
                goto out;
996
            }
997

998
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.device_path",
999
                              volcount, brick_count);
1000
            ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->device_path);
1001
            if (ret) {
1002
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1003
                       "Failed to set %s", key);
1004
                goto out;
1005
            }
1006

1007
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.fs_type",
1008
                              volcount, brick_count);
1009
            ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->fstype);
1010
            if (ret) {
1011
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1012
                       "Failed to set %s", key);
1013
                goto out;
1014
            }
1015

1016
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.snap_type",
1017
                              volcount, brick_count);
1018
            ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->snap_type);
1019
            if (ret) {
1020
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1021
                       "Failed to set %s", key);
1022
                goto out;
1023
            }
1024

1025
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.mnt_opts",
1026
                              volcount, brick_count);
1027
            ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->mnt_opts);
1028
            if (ret) {
1029
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1030
                       "Failed to set %s", key);
1031
                goto out;
1032
            }
1033
        }
1034

1035
        keylen = snprintf(key, sizeof(key), "snap%d.brick_count", volcount);
1036
        ret = dict_set_int32n(rsp_dict, key, keylen, brick_count);
1037
        if (ret) {
1038
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1039
                   "Failed to set %s", key);
1040
            goto out;
1041
        }
1042
    }
1043

1044
    ret = dict_set_int32_sizen(rsp_dict, "volcount", volcount);
1045
    if (ret) {
1046
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1047
               "Failed to set %s", key);
1048
        goto out;
1049
    }
1050

1051
out:
1052
    return ret;
1053
}
1054

1055
int
1056
snap_max_hard_limits_validate(dict_t *dict, char *volname, uint64_t value,
1057
                              char **op_errstr)
1058
{
1059
    char err_str[PATH_MAX] = "";
1060
    glusterd_conf_t *conf = NULL;
1061
    glusterd_volinfo_t *volinfo = NULL;
1062
    int ret = -1;
1063
    uint64_t max_limit = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
1064
    xlator_t *this = THIS;
1065
    uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
1066

1067
    GF_ASSERT(dict);
1068
    GF_ASSERT(op_errstr);
1069

1070
    conf = this->private;
1071

1072
    GF_ASSERT(conf);
1073

1074
    if (volname) {
1075
        ret = glusterd_volinfo_find(volname, &volinfo);
1076
        if (!ret) {
1077
            if (volinfo->is_snap_volume) {
1078
                ret = -1;
1079
                snprintf(err_str, PATH_MAX,
1080
                         "%s is a snap volume. Configuring "
1081
                         "snap-max-hard-limit for a snap "
1082
                         "volume is prohibited.",
1083
                         volname);
1084
                goto out;
1085
            }
1086
        }
1087
    }
1088

1089
    /* "snap-max-hard-limit" might not be set by user explicitly,
1090
     * in that case it's better to use the default value.
1091
     * Hence not erroring out if Key is not found.
1092
     */
1093
    ret = dict_get_uint64(conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
1094
                          &opt_hard_max);
1095
    if (ret) {
1096
        ret = 0;
1097
        gf_msg_debug(this->name, 0,
1098
                     "%s is not present in "
1099
                     "opts dictionary",
1100
                     GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
1101
    }
1102

1103
    /* volume snap-max-hard-limit cannot exceed system snap-max-hard-limit.
1104
     * Hence during prevalidate following checks are made to ensure the
1105
     * snap-max-hard-limit set on one particular volume does not
1106
     * exceed snap-max-hard-limit set globally (system limit).
1107
     */
1108
    if (value && volname) {
1109
        max_limit = opt_hard_max;
1110
    }
1111

1112
    if (value > max_limit) {
1113
        ret = -1;
1114
        snprintf(err_str, PATH_MAX,
1115
                 "Invalid snap-max-hard-limit "
1116
                 "%" PRIu64 ". Expected range 1 - %" PRIu64,
1117
                 value, max_limit);
1118
        goto out;
1119
    }
1120

1121
    ret = 0;
1122
out:
1123
    if (ret) {
1124
        *op_errstr = gf_strdup(err_str);
1125
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
1126
               err_str);
1127
    }
1128
    return ret;
1129
}
1130

1131
int
1132
glusterd_snapshot_config_prevalidate(dict_t *dict, char **op_errstr,
1133
                                     uint32_t *op_errno)
1134
{
1135
    char *volname = NULL;
1136
    glusterd_volinfo_t *volinfo = NULL;
1137
    xlator_t *this = THIS;
1138
    int ret = -1;
1139
    int config_command = 0;
1140
    char err_str[PATH_MAX] = "";
1141
    glusterd_conf_t *conf = NULL;
1142
    uint64_t hard_limit = 0;
1143
    uint64_t soft_limit = 0;
1144
    gf_loglevel_t loglevel = GF_LOG_ERROR;
1145
    uint64_t max_limit = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
1146
    int32_t cur_auto_delete = 0;
1147
    int32_t req_auto_delete = 0;
1148
    int32_t cur_snap_activate = 0;
1149
    int32_t req_snap_activate = 0;
1150

1151
    GF_ASSERT(dict);
1152
    GF_ASSERT(op_errstr);
1153
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
1154

1155
    conf = this->private;
1156

1157
    GF_ASSERT(conf);
1158

1159
    ret = dict_get_int32(dict, "config-command", &config_command);
1160
    if (ret) {
1161
        snprintf(err_str, sizeof(err_str), "failed to get config-command type");
1162
        goto out;
1163
    }
1164

1165
    if (config_command != GF_SNAP_CONFIG_TYPE_SET) {
1166
        ret = 0;
1167
        goto out;
1168
    }
1169

1170
    ret = dict_get_str(dict, "volname", &volname);
1171
    if (volname) {
1172
        ret = glusterd_volinfo_find(volname, &volinfo);
1173
        if (ret) {
1174
            snprintf(err_str, sizeof(err_str), "Volume (%s) does not exist.",
1175
                     volname);
1176
            *op_errno = EG_NOVOL;
1177
            goto out;
1178
        }
1179
    }
1180

1181
    /* config values snap-max-hard-limit and snap-max-soft-limit are
1182
     * optional and hence we are not erroring out if values are not
1183
     * present
1184
     */
1185
    gd_get_snap_conf_values_if_present(dict, &hard_limit, &soft_limit);
1186

1187
    if (hard_limit) {
1188
        /* Validations for snap-max-hard-limits */
1189
        ret = snap_max_hard_limits_validate(dict, volname, hard_limit,
1190
                                            op_errstr);
1191
        if (ret) {
1192
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HARD_LIMIT_SET_FAIL,
1193
                   "snap-max-hard-limit validation failed.");
1194
            *op_errno = EINVAL;
1195
            goto out;
1196
        }
1197
    }
1198

1199
    if (soft_limit) {
1200
        max_limit = GLUSTERD_SNAPS_MAX_SOFT_LIMIT_PERCENT;
1201
        if (soft_limit > max_limit) {
1202
            ret = -1;
1203
            snprintf(err_str, PATH_MAX,
1204
                     "Invalid "
1205
                     "snap-max-soft-limit "
1206
                     "%" PRIu64 ". Expected range 1 - %" PRIu64,
1207
                     soft_limit, max_limit);
1208
            *op_errno = EINVAL;
1209
            goto out;
1210
        }
1211
    }
1212

1213
    if (hard_limit || soft_limit) {
1214
        ret = 0;
1215
        goto out;
1216
    }
1217

1218
    if (dict_get_sizen(dict, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE)) {
1219
        req_auto_delete = dict_get_str_boolean(
1220
            dict, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, _gf_false);
1221
        if (req_auto_delete < 0) {
1222
            ret = -1;
1223
            snprintf(err_str, sizeof(err_str),
1224
                     "Please enter a "
1225
                     "valid boolean value for auto-delete");
1226
            *op_errno = EINVAL;
1227
            goto out;
1228
        }
1229

1230
        /* Ignoring the error as the auto-delete is optional and
1231
           might not be present in the options dictionary.*/
1232
        cur_auto_delete = dict_get_str_boolean(
1233
            conf->opts, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, _gf_false);
1234

1235
        if (cur_auto_delete == req_auto_delete) {
1236
            ret = -1;
1237
            if (cur_auto_delete == _gf_true)
1238
                snprintf(err_str, sizeof(err_str),
1239
                         "auto-delete is already enabled");
1240
            else
1241
                snprintf(err_str, sizeof(err_str),
1242
                         "auto-delete is already disabled");
1243
            *op_errno = EINVAL;
1244
            goto out;
1245
        }
1246
    } else if (dict_get_sizen(dict, GLUSTERD_STORE_KEY_SNAP_ACTIVATE)) {
1247
        req_snap_activate = dict_get_str_boolean(
1248
            dict, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, _gf_false);
1249
        if (req_snap_activate < 0) {
1250
            ret = -1;
1251
            snprintf(err_str, sizeof(err_str),
1252
                     "Please enter a "
1253
                     "valid boolean value for activate-on-create");
1254
            *op_errno = EINVAL;
1255
            goto out;
1256
        }
1257

1258
        /* Ignoring the error as the activate-on-create is optional and
1259
           might not be present in the options dictionary.*/
1260
        cur_snap_activate = dict_get_str_boolean(
1261
            conf->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, _gf_false);
1262

1263
        if (cur_snap_activate == req_snap_activate) {
1264
            ret = -1;
1265
            if (cur_snap_activate == _gf_true)
1266
                snprintf(err_str, sizeof(err_str),
1267
                         "activate-on-create is already enabled");
1268
            else
1269
                snprintf(err_str, sizeof(err_str),
1270
                         "activate-on-create is already disabled");
1271
            *op_errno = EINVAL;
1272
            goto out;
1273
        }
1274
    } else {
1275
        ret = -1;
1276
        snprintf(err_str, sizeof(err_str), "Invalid option");
1277
        *op_errno = EINVAL;
1278
        goto out;
1279
    }
1280

1281
    ret = 0;
1282
out:
1283

1284
    if (ret && err_str[0] != '\0') {
1285
        gf_msg(this->name, loglevel, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
1286
               err_str);
1287
        *op_errstr = gf_strdup(err_str);
1288
    }
1289

1290
    return ret;
1291
}
1292

1293
/* This function will be called from RPC handler routine.
1294
 * This function is responsible for getting the requested
1295
 * snapshot config into the dictionary.
1296
 *
1297
 * @param req   RPC request object. Required for sending a response back.
1298
 * @param op    glusterd operation. Required for sending a response back.
1299
 * @param dict  pointer to dictionary which will contain both
1300
 *              request and response key-pair values.
1301
 * @return -1 on error and 0 on success
1302
 */
1303
int
1304
glusterd_handle_snapshot_config(rpcsvc_request_t *req, glusterd_op_t op,
1305
                                dict_t *dict, char *err_str, size_t len)
1306
{
1307
    int32_t ret = -1;
1308
    char *volname = NULL;
1309
    xlator_t *this = THIS;
1310
    int config_command = 0;
1311

1312
    GF_VALIDATE_OR_GOTO(this->name, req, out);
1313
    GF_VALIDATE_OR_GOTO(this->name, dict, out);
1314

1315
    /* TODO : Type of lock to be taken when we are setting
1316
     * limits system wide
1317
     */
1318
    ret = dict_get_int32(dict, "config-command", &config_command);
1319
    if (ret) {
1320
        snprintf(err_str, len, "Failed to get config-command type");
1321
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1322
                "Key=config-command", NULL);
1323
        goto out;
1324
    }
1325

1326
    ret = dict_get_str(dict, "volname", &volname);
1327

1328
    switch (config_command) {
1329
        case GF_SNAP_CONFIG_TYPE_SET:
1330
            if (!volname) {
1331
                ret = dict_set_int32_sizen(dict, "hold_vol_locks", _gf_false);
1332
                if (ret) {
1333
                    gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1334
                           "Unable to set hold_vol_locks value "
1335
                           "as _gf_false");
1336
                    goto out;
1337
                }
1338
            }
1339
            ret = glusterd_mgmt_v3_initiate_all_phases(req, op, dict);
1340
            break;
1341
        case GF_SNAP_CONFIG_DISPLAY:
1342
            /* Reading data from local node only */
1343
            ret = snap_max_limits_display_commit(dict, volname, err_str, len);
1344
            if (ret) {
1345
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HARD_LIMIT_SET_FAIL,
1346
                       "snap-max-limit "
1347
                       "display commit failed.");
1348
                goto out;
1349
            }
1350

1351
            /* If everything is successful then send the response
1352
             * back to cli
1353
             */
1354
            ret = glusterd_op_send_cli_response(op, 0, 0, req, dict, err_str);
1355
            if (ret) {
1356
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
1357
                       "Failed to send cli "
1358
                       "response");
1359
                goto out;
1360
            }
1361

1362
            break;
1363
        default:
1364
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
1365
                   "Unknown config type");
1366
            ret = -1;
1367
            break;
1368
    }
1369
out:
1370
    return ret;
1371
}
1372
int
1373
glusterd_snap_create_clone_pre_val_use_rsp_dict(dict_t *dst, dict_t *src)
1374
{
1375
    char *snap_brick_dir = NULL;
1376
    char *snap_device = NULL;
1377
    char key[64] = "";
1378
    int keylen;
1379
    char *value = "";
1380
    char snapbrckcnt[PATH_MAX] = "";
1381
    char snapbrckord[PATH_MAX] = "";
1382
    int ret = -1;
1383
    int64_t i = -1;
1384
    int64_t j = -1;
1385
    int64_t volume_count = 0;
1386
    int64_t brick_count = 0;
1387
    int64_t brick_order = 0;
1388
    xlator_t *this = THIS;
1389
    int32_t brick_online = 0;
1390

1391
    GF_ASSERT(dst);
1392
    GF_ASSERT(src);
1393

1394
    ret = dict_get_int64(src, "volcount", &volume_count);
1395
    if (ret) {
1396
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1397
               "failed to "
1398
               "get the volume count");
1399
        goto out;
1400
    }
1401

1402
    for (i = 0; i < volume_count; i++) {
1403
        ret = snprintf(snapbrckcnt, sizeof(snapbrckcnt) - 1,
1404
                       "vol%" PRId64 "_brickcount", i + 1);
1405
        ret = dict_get_int64(src, snapbrckcnt, &brick_count);
1406
        if (ret) {
1407
            gf_msg_trace(this->name, 0,
1408
                         "No bricks for this volume in this dict");
1409
            continue;
1410
        }
1411

1412
        keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_plugin",
1413
                          i + 1);
1414
        ret = dict_get_strn(src, key, keylen, &value);
1415
        if (ret) {
1416
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1417
                   "Unable to fetch %s", key);
1418
            continue;
1419
        }
1420

1421
        ret = dict_set_dynstr_with_alloc(dst, key, value);
1422
        if (ret) {
1423
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1424
                   "Failed to set %s", key);
1425
            goto out;
1426
        }
1427

1428
        for (j = 0; j < brick_count; j++) {
1429
            /* Fetching data from source dict */
1430
            snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%" PRId64, i + 1,
1431
                     j);
1432
            ret = dict_get_ptr(src, key, (void **)&snap_brick_dir);
1433
            if (ret) {
1434
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1435
                       "Unable to fetch %s", key);
1436
                continue;
1437
            }
1438

1439
            /* Fetching brick order from source dict */
1440
            snprintf(snapbrckord, sizeof(snapbrckord) - 1,
1441
                     "vol%" PRId64 ".brick%" PRId64 ".order", i + 1, j);
1442
            ret = dict_get_int64(src, snapbrckord, &brick_order);
1443
            if (ret) {
1444
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1445
                       "Failed to get brick order");
1446
                goto out;
1447
            }
1448

1449
            snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%" PRId64, i + 1,
1450
                     brick_order);
1451
            ret = dict_set_dynstr_with_alloc(dst, key, snap_brick_dir);
1452
            if (ret) {
1453
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1454
                       "Failed to set %s", key);
1455
                goto out;
1456
            }
1457

1458
            keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%" PRId64,
1459
                              i + 1, j);
1460
            ret = dict_get_strn(src, key, keylen, &value);
1461
            if (ret) {
1462
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1463
                       "Unable to fetch %s", key);
1464
                continue;
1465
            }
1466

1467
            snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%" PRId64, i + 1,
1468
                     brick_order);
1469
            ret = dict_set_dynstr_with_alloc(dst, key, value);
1470
            if (ret) {
1471
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1472
                       "Failed to set %s", key);
1473
                goto out;
1474
            }
1475

1476
            keylen = snprintf(key, sizeof(key),
1477
                              "vol%" PRId64 ".snap_type%" PRId64, i + 1, j);
1478
            ret = dict_get_strn(src, key, keylen, &value);
1479
            if (ret) {
1480
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1481
                       "Unable to fetch %s", key);
1482
                continue;
1483
            }
1484

1485
            snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%" PRId64,
1486
                     i + 1, brick_order);
1487
            ret = dict_set_dynstr_with_alloc(dst, key, value);
1488
            if (ret) {
1489
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1490
                       "Failed to set %s", key);
1491
                goto out;
1492
            }
1493

1494
            keylen = snprintf(key, sizeof(key),
1495
                              "vol%" PRId64 ".mnt_opts%" PRId64, i + 1, j);
1496
            ret = dict_get_strn(src, key, keylen, &value);
1497
            if (ret) {
1498
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1499
                       "Unable to fetch %s", key);
1500
                continue;
1501
            }
1502

1503
            snprintf(key, sizeof(key), "vol%" PRId64 ".mnt_opts%" PRId64, i + 1,
1504
                     brick_order);
1505
            ret = dict_set_dynstr_with_alloc(dst, key, value);
1506
            if (ret) {
1507
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1508
                       "Failed to set %s", key);
1509
                goto out;
1510
            }
1511

1512
            snprintf(key, sizeof(key),
1513
                     "vol%" PRId64 ".brick_snapdevice%" PRId64, i + 1, j);
1514
            ret = dict_get_ptr(src, key, (void **)&snap_device);
1515
            if (ret) {
1516
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1517
                       "Unable to fetch snap_device");
1518
                goto out;
1519
            }
1520

1521
            snprintf(key, sizeof(key),
1522
                     "vol%" PRId64 ".brick_snapdevice%" PRId64, i + 1,
1523
                     brick_order);
1524
            ret = dict_set_dynstr_with_alloc(dst, key, snap_device);
1525
            if (ret) {
1526
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1527
                       "Failed to set %s", key);
1528
                goto out;
1529
            }
1530

1531
            keylen = snprintf(key, sizeof(key),
1532
                              "vol%" PRId64 ".brick%" PRId64 ".status", i + 1,
1533
                              brick_order);
1534
            ret = dict_get_int32n(src, key, keylen, &brick_online);
1535
            if (ret) {
1536
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1537
                       "failed to "
1538
                       "get the brick status");
1539
                goto out;
1540
            }
1541

1542
            ret = dict_set_int32n(dst, key, keylen, brick_online);
1543
            if (ret) {
1544
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1545
                       "failed to "
1546
                       "set the brick status");
1547
                goto out;
1548
            }
1549
            brick_online = 0;
1550
        }
1551
    }
1552
    ret = 0;
1553
out:
1554

1555
    gf_msg_trace(this->name, 0, "Returning %d", ret);
1556
    return ret;
1557
}
1558

1559
/* Aggregate brickinfo's of the snap volumes to be restored from */
1560
int32_t
1561
glusterd_snap_restore_use_rsp_dict(dict_t *dst, dict_t *src)
1562
{
1563
    char key[64] = "";
1564
    int keylen;
1565
    char *strvalue = NULL;
1566
    int32_t value = -1;
1567
    int32_t i = -1;
1568
    int32_t j = -1;
1569
    int32_t vol_count = -1;
1570
    int32_t brickcount = -1;
1571
    int32_t ret = -1;
1572
    xlator_t *this = THIS;
1573

1574
    if (!dst || !src) {
1575
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
1576
               "Source or Destination "
1577
               "dict is empty.");
1578
        goto out;
1579
    }
1580

1581
    ret = dict_get_int32(src, "volcount", &vol_count);
1582
    if (ret) {
1583
        gf_msg_debug(this->name, 0, "No volumes");
1584
        ret = 0;
1585
        goto out;
1586
    }
1587

1588
    for (i = 1; i <= vol_count; i++) {
1589
        keylen = snprintf(key, sizeof(key), "snap%d.brick_count", i);
1590
        ret = dict_get_int32n(src, key, keylen, &brickcount);
1591
        if (ret) {
1592
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1593
                   "Failed to get %s", key);
1594
            goto out;
1595
        }
1596

1597
        for (j = 1; j <= brickcount; j++) {
1598
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.path", i, j);
1599
            ret = dict_get_strn(src, key, keylen, &strvalue);
1600
            if (ret) {
1601
                /* The brickinfo will be present in
1602
                 * another rsp_dict */
1603
                gf_msg_debug(this->name, 0, "%s not present", key);
1604
                ret = 0;
1605
                continue;
1606
            }
1607
            ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1608
            if (ret) {
1609
                gf_msg_debug(this->name, 0, "Failed to set %s", key);
1610
                goto out;
1611
            }
1612

1613
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.snap_status", i,
1614
                              j);
1615
            ret = dict_get_int32n(src, key, keylen, &value);
1616
            if (ret) {
1617
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1618
                       "Failed to get %s", key);
1619
                goto out;
1620
            }
1621
            ret = dict_set_int32n(dst, key, keylen, value);
1622
            if (ret) {
1623
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1624
                       "Failed to set %s", key);
1625
                goto out;
1626
            }
1627

1628
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.origin_path", i,
1629
                              j);
1630
            ret = dict_get_strn(src, key, keylen, &strvalue);
1631
            if (ret) {
1632
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1633
                       "Failed to get %s", key);
1634
                goto out;
1635
            }
1636
            ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1637
            if (ret) {
1638
                gf_msg_debug(this->name, 0, "Failed to set %s", key);
1639
                goto out;
1640
            }
1641

1642
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.device_path", i,
1643
                              j);
1644
            ret = dict_get_strn(src, key, keylen, &strvalue);
1645
            if (ret) {
1646
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1647
                       "Failed to get %s", key);
1648
            } else {
1649
                ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1650
                if (ret) {
1651
                    gf_msg_debug(this->name, 0, "Failed to set %s", key);
1652
                    goto out;
1653
                }
1654
            }
1655

1656
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.fs_type", i, j);
1657
            ret = dict_get_strn(src, key, keylen, &strvalue);
1658
            if (ret) {
1659
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1660
                       "Failed to get %s", key);
1661
                goto out;
1662
            }
1663
            ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1664
            if (ret) {
1665
                gf_msg_debug(this->name, 0, "Failed to set %s", key);
1666
                goto out;
1667
            }
1668

1669
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.snap_type", i,
1670
                              j);
1671
            ret = dict_get_strn(src, key, keylen, &strvalue);
1672
            if (ret) {
1673
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1674
                       "Failed to get %s", key);
1675
                goto out;
1676
            }
1677
            ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1678
            if (ret) {
1679
                gf_msg_debug(this->name, 0, "Failed to set %s", key);
1680
                goto out;
1681
            }
1682

1683
            keylen = snprintf(key, sizeof(key), "snap%d.brick%d.mnt_opts", i,
1684
                              j);
1685
            ret = dict_get_strn(src, key, keylen, &strvalue);
1686
            if (ret) {
1687
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1688
                       "Failed to get %s", key);
1689
                goto out;
1690
            }
1691
            ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1692
            if (ret) {
1693
                gf_msg_debug(this->name, 0, "Failed to set %s", key);
1694
                goto out;
1695
            }
1696
        }
1697
    }
1698

1699
out:
1700
    gf_msg_trace(this->name, 0, "Returning %d", ret);
1701
    return ret;
1702
}
1703

1704
int
1705
glusterd_snap_pre_validate_use_rsp_dict(dict_t *dst, dict_t *src)
1706
{
1707
    int ret = -1;
1708
    int32_t snap_command = 0;
1709
    xlator_t *this = THIS;
1710

1711
    if (!dst || !src) {
1712
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
1713
               "Source or Destination "
1714
               "dict is empty.");
1715
        goto out;
1716
    }
1717

1718
    ret = dict_get_int32(dst, "type", &snap_command);
1719
    if (ret) {
1720
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1721
               "unable to get the type of "
1722
               "the snapshot command");
1723
        goto out;
1724
    }
1725

1726
    switch (snap_command) {
1727
        case GF_SNAP_OPTION_TYPE_CREATE:
1728
        case GF_SNAP_OPTION_TYPE_CLONE:
1729
            ret = glusterd_snap_create_clone_pre_val_use_rsp_dict(dst, src);
1730
            if (ret) {
1731
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1732
                       "Unable to use "
1733
                       "rsp dict");
1734
                goto out;
1735
            }
1736
            break;
1737
        case GF_SNAP_OPTION_TYPE_RESTORE:
1738
            ret = glusterd_snap_restore_use_rsp_dict(dst, src);
1739
            if (ret) {
1740
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_RSP_DICT_USE_FAIL,
1741
                       "Unable to use "
1742
                       "rsp dict");
1743
                goto out;
1744
            }
1745
            break;
1746
        default:
1747
            break;
1748
    }
1749

1750
    ret = 0;
1751
out:
1752
    gf_msg_debug(this->name, 0, "Returning %d", ret);
1753
    return ret;
1754
}
1755

1756
static int
1757
glusterd_add_brick_status_to_dict(dict_t *dict, glusterd_volinfo_t *volinfo,
1758
                                  glusterd_brickinfo_t *brickinfo,
1759
                                  char *key_prefix)
1760
{
1761
    char pidfile[PATH_MAX] = "";
1762
    int32_t brick_online = 0;
1763
    pid_t pid = 0;
1764
    xlator_t *this = THIS;
1765
    glusterd_conf_t *conf = NULL;
1766
    int ret = -1;
1767

1768
    GF_ASSERT(dict);
1769
    GF_ASSERT(volinfo);
1770
    GF_ASSERT(brickinfo);
1771

1772
    conf = this->private;
1773
    GF_ASSERT(conf);
1774

1775
    if (!key_prefix) {
1776
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
1777
               "key prefix is NULL");
1778
        goto out;
1779
    }
1780

1781
    GLUSTERD_GET_BRICK_PIDFILE(pidfile, volinfo, brickinfo, conf);
1782

1783
    brick_online = gf_is_service_running(pidfile, &pid);
1784

1785
    ret = dict_set_int32(dict, key_prefix, brick_online);
1786
    if (ret) {
1787
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1788
               "Failed to set %s", key_prefix);
1789
        goto out;
1790
    }
1791
    brick_online = 0;
1792

1793
    ret = 0;
1794

1795
out:
1796
    return ret;
1797
}
1798

1799
int
1800
glusterd_snap_create_clone_common_prevalidate(
1801
    dict_t *rsp_dict, int flags, char *snapname, char *err_str,
1802
    char *snap_volname, int64_t volcount, glusterd_volinfo_t *volinfo,
1803
    gf_loglevel_t *loglevel, int clone, uint32_t *op_errno)
1804
{
1805
    char device[NAME_MAX] = "";
1806
    char key[128] = "";
1807
    int ret = -1;
1808
    int64_t i = 1;
1809
    int64_t brick_order = 0;
1810
    int64_t brick_count = 0;
1811
    xlator_t *this = THIS;
1812
    glusterd_conf_t *conf = NULL;
1813
    glusterd_brickinfo_t *brickinfo = NULL;
1814

1815
    conf = this->private;
1816
    GF_ASSERT(conf);
1817
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
1818

1819
    if (!snapname || !volinfo) {
1820
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
1821
               "Failed to validate "
1822
               "snapname or volume information");
1823
        ret = -1;
1824
        goto out;
1825
    }
1826

1827
    cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
1828
    {
1829
        if (gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
1830
            brick_order++;
1831
            continue;
1832
        }
1833

1834
        if (!glusterd_is_brick_started(brickinfo)) {
1835
            if (!clone) {
1836
                snprintf(err_str, PATH_MAX,
1837
                         "One or more bricks are not running. "
1838
                         "Please run volume status command to see "
1839
                         "brick status.\n"
1840
                         "All bricks have to be online to take a snapshot."
1841
                         "Please start the stopped brick "
1842
                         "and then issue snapshot create command.");
1843
                gf_smsg(
1844
                    this->name, GF_LOG_ERROR, errno, GD_MSG_BRICK_NOT_RUNNING,
1845
                    "Please run volume status command to see brick "
1846
                    "status. All bricks have to be online to take a snapshot."
1847
                    "Please start the stopped brick and then issue "
1848
                    "snapshot create command.",
1849
                    NULL);
1850
            } else {
1851
                snprintf(err_str, PATH_MAX,
1852
                         "One or more bricks are not running. "
1853
                         "Please run snapshot status command to see "
1854
                         "brick status.\n"
1855
                         "Please start the stopped brick "
1856
                         "and then issue snapshot clone "
1857
                         "command ");
1858
                gf_smsg(this->name, GF_LOG_ERROR, errno,
1859
                        GD_MSG_BRICK_NOT_RUNNING,
1860
                        "Please run snapshot status command to see brick "
1861
                        "status. Please start the stopped brick and then issue "
1862
                        "snapshot clone command.",
1863
                        NULL);
1864
            }
1865
            *op_errno = EG_BRCKDWN;
1866
            ret = -1;
1867
            goto out;
1868
        }
1869

1870
        if (!glusterd_snapshot_probe(brickinfo->path, brickinfo)) {
1871
            snprintf(err_str, PATH_MAX,
1872
                     "Snapshots not supported for"
1873
                     " all bricks in volume %s.",
1874
                     volinfo->volname);
1875
            ret = -1;
1876
            goto out;
1877
        }
1878

1879
        snprintf(key, sizeof(key), "vol%" PRId64 ".snap_plugin", i);
1880
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->snap->name);
1881
        if (ret) {
1882
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1883
                   "Failed to set %s", key);
1884
            goto out;
1885
        }
1886

1887
        snprintf(device, sizeof(device), "%s_%" PRId64, snap_volname,
1888
                 brick_order);
1889
        snprintf(key, sizeof(key), "vol%" PRId64 ".brick_snapdevice%" PRId64, i,
1890
                 brick_count);
1891
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, device);
1892
        if (ret) {
1893
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1894
                   "Failed to set %s", key);
1895
            goto out;
1896
        }
1897

1898
        ret = glusterd_update_mntopts(brickinfo->path, brickinfo);
1899
        if (ret) {
1900
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRK_MOUNTOPTS_FAIL,
1901
                   "Failed to "
1902
                   "update mount options for %s brick",
1903
                   brickinfo->path);
1904
        }
1905

1906
        snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%" PRId64, i,
1907
                 brick_count);
1908
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->fstype);
1909
        if (ret) {
1910
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1911
                   "Failed to set %s", key);
1912
            goto out;
1913
        }
1914

1915
        snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%" PRId64, i,
1916
                 brick_count);
1917
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->snap_type);
1918
        if (ret) {
1919
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1920
                   "Failed to set %s", key);
1921
            goto out;
1922
        }
1923

1924
        snprintf(key, sizeof(key), "vol%" PRId64 ".mnt_opts%" PRId64, i,
1925
                 brick_count);
1926
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->mnt_opts);
1927
        if (ret) {
1928
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1929
                   "Failed to set %s", key);
1930
            goto out;
1931
        }
1932

1933
        snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%" PRId64, i,
1934
                 brick_count);
1935
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->mount_dir);
1936
        if (ret) {
1937
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1938
                   "Failed to set %s", key);
1939
            goto out;
1940
        }
1941

1942
        snprintf(key, sizeof(key) - 1, "vol%" PRId64 ".brick%" PRId64 ".order",
1943
                 i, brick_count);
1944
        ret = dict_set_int64(rsp_dict, key, brick_order);
1945
        if (ret) {
1946
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1947
                   "Failed to set %s", key);
1948
            goto out;
1949
        }
1950

1951
        snprintf(key, sizeof(key), "vol%" PRId64 ".brick%" PRId64 ".status", i,
1952
                 brick_order);
1953

1954
        ret = glusterd_add_brick_status_to_dict(rsp_dict, volinfo, brickinfo,
1955
                                                key);
1956
        if (ret) {
1957
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1958
                   "failed to "
1959
                   "add brick status to dict");
1960
            goto out;
1961
        }
1962
        brick_count++;
1963
        brick_order++;
1964
    }
1965
    snprintf(key, sizeof(key) - 1, "vol%" PRId64 "_brickcount", volcount);
1966
    ret = dict_set_int64(rsp_dict, key, brick_count);
1967
    if (ret) {
1968
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1969
               "Failed to set %s", key);
1970
        goto out;
1971
    }
1972
    ret = 0;
1973
out:
1974

1975
    return ret;
1976
}
1977

1978
int
1979
glusterd_snapshot_clone_prevalidate(dict_t *dict, char **op_errstr,
1980
                                    dict_t *rsp_dict, uint32_t *op_errno)
1981
{
1982
    char *clonename = NULL;
1983
    char *snapname = NULL;
1984
    char device_name[64] = "";
1985
    glusterd_snap_t *snap = NULL;
1986
    char err_str[PATH_MAX] = "";
1987
    int ret = -1;
1988
    int64_t volcount = 1;
1989
    glusterd_volinfo_t *snap_vol = NULL;
1990
    xlator_t *this = THIS;
1991
    uuid_t *snap_volid = NULL;
1992
    gf_loglevel_t loglevel = GF_LOG_ERROR;
1993
    glusterd_volinfo_t *volinfo = NULL;
1994

1995
    GF_ASSERT(op_errstr);
1996
    GF_ASSERT(dict);
1997
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
1998

1999
    ret = dict_get_str(dict, "clonename", &clonename);
2000
    if (ret) {
2001
        snprintf(err_str, sizeof(err_str),
2002
                 "Failed to "
2003
                 "get the clone name");
2004
        goto out;
2005
    }
2006

2007
    ret = dict_get_str(dict, "snapname", &snapname);
2008
    if (ret) {
2009
        snprintf(err_str, sizeof(err_str), "Failed to get snapname");
2010
        goto out;
2011
    }
2012

2013
    ret = glusterd_volinfo_find(clonename, &volinfo);
2014
    if (!ret) {
2015
        ret = -1;
2016
        snprintf(err_str, sizeof(err_str),
2017
                 "Volume with name:%s "
2018
                 "already exists",
2019
                 clonename);
2020
        *op_errno = EG_VOLEXST;
2021
        goto out;
2022
    }
2023
    /* need to find snap volinfo*/
2024
    snap = glusterd_find_snap_by_name(snapname);
2025
    if (!snap) {
2026
        ret = -1;
2027
        snprintf(err_str, sizeof(err_str),
2028
                 "Failed to find :%s "
2029
                 "snap",
2030
                 snapname);
2031
        goto out;
2032
    }
2033

2034
    /* TODO : As of now there is only one volume in snapshot.
2035
     * Change this when multiple volume snapshot is introduced
2036
     */
2037
    snap_vol = list_entry(snap->volumes.next, glusterd_volinfo_t, vol_list);
2038
    if (!snap_vol) {
2039
        gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
2040
               "Failed to get snap "
2041
               "volinfo %s",
2042
               snap->snapname);
2043
        goto out;
2044
    }
2045

2046
    if (!glusterd_is_volume_started(snap_vol)) {
2047
        snprintf(err_str, sizeof(err_str),
2048
                 "Snapshot %s is "
2049
                 "not activated",
2050
                 snap->snapname);
2051
        loglevel = GF_LOG_WARNING;
2052
        *op_errno = EG_VOLSTP;
2053
        goto out;
2054
    }
2055

2056
    ret = dict_get_bin(dict, "vol1_volid", (void **)&snap_volid);
2057
    if (ret) {
2058
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2059
               "Unable to fetch snap_volid");
2060
        goto out;
2061
    }
2062

2063
    GLUSTERD_GET_UUID_NOHYPHEN(device_name, *snap_volid);
2064

2065
    /* Adding snap bricks mount paths to the dict */
2066
    ret = glusterd_snap_create_clone_common_prevalidate(
2067
        rsp_dict, 0, snapname, err_str, device_name, 1, snap_vol, &loglevel, 1,
2068
        op_errno);
2069
    if (ret) {
2070
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PRE_VALIDATION_FAIL,
2071
               "Failed to pre validate");
2072
        goto out;
2073
    }
2074

2075
    ret = dict_set_int64(rsp_dict, "volcount", volcount);
2076
    if (ret) {
2077
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2078
               "Failed to set volcount");
2079
        goto out;
2080
    }
2081

2082
out:
2083

2084
    if (ret && err_str[0] != '\0') {
2085
        gf_msg(this->name, loglevel, 0, GD_MSG_SNAP_CLONE_PREVAL_FAILED, "%s",
2086
               err_str);
2087
        *op_errstr = gf_strdup(err_str);
2088
    }
2089

2090
    gf_msg_trace(this->name, 0, "Returning %d", ret);
2091
    return ret;
2092
}
2093

2094
/*
2095
 * gd_vol_is_geo_rep_active:
2096
 *      This function checks for any running geo-rep session for
2097
 *      the volume given.
2098
 *
2099
 * Return Value:
2100
 *      _gf_true : If any running geo-rep session.
2101
 *      _gf_false: If no running geo-rep session.
2102
 */
2103

2104
static gf_boolean_t
2105
gd_vol_is_geo_rep_active(glusterd_volinfo_t *volinfo)
2106
{
2107
    gf_boolean_t active = _gf_false;
2108

2109
    GF_ASSERT(volinfo);
2110

2111
    if (volinfo->gsync_active_secondaries &&
2112
        volinfo->gsync_active_secondaries->count > 0)
2113
        active = _gf_true;
2114

2115
    return active;
2116
}
2117

2118
int
2119
glusterd_snapshot_create_prevalidate(dict_t *dict, char **op_errstr,
2120
                                     dict_t *rsp_dict, uint32_t *op_errno)
2121
{
2122
    char *volname = NULL;
2123
    char *snapname = NULL;
2124
    char key[64] = "";
2125
    int keylen;
2126
    char snap_volname[64] = "";
2127
    char err_str[PATH_MAX] = "";
2128
    int ret = -1;
2129
    int64_t i = 0;
2130
    int64_t volcount = 0;
2131
    glusterd_volinfo_t *volinfo = NULL;
2132
    xlator_t *this = THIS;
2133
    uuid_t *snap_volid = NULL;
2134
    gf_loglevel_t loglevel = GF_LOG_ERROR;
2135
    glusterd_conf_t *conf = NULL;
2136
    int64_t effective_max_limit = 0;
2137
    int flags = 0;
2138
    uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
2139
    char *description = NULL;
2140

2141
    GF_ASSERT(op_errstr);
2142
    conf = this->private;
2143
    GF_ASSERT(conf);
2144
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
2145

2146
    ret = dict_get_int64(dict, "volcount", &volcount);
2147
    if (ret) {
2148
        snprintf(err_str, sizeof(err_str),
2149
                 "Failed to "
2150
                 "get the volume count");
2151
        goto out;
2152
    }
2153
    if (volcount <= 0) {
2154
        snprintf(err_str, sizeof(err_str),
2155
                 "Invalid volume count %" PRId64 " supplied", volcount);
2156
        ret = -1;
2157
        goto out;
2158
    }
2159

2160
    ret = dict_get_str(dict, "snapname", &snapname);
2161
    if (ret) {
2162
        snprintf(err_str, sizeof(err_str), "Failed to get snapname");
2163
        goto out;
2164
    }
2165

2166
    ret = dict_get_str(dict, "description", &description);
2167
    if (description && !(*description)) {
2168
        /* description should have a non-null value */
2169
        ret = -1;
2170
        snprintf(err_str, sizeof(err_str),
2171
                 "Snapshot cannot be "
2172
                 "created with empty description");
2173
        goto out;
2174
    }
2175

2176
    ret = dict_get_int32(dict, "flags", &flags);
2177
    if (ret) {
2178
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2179
               "Unable to get flags");
2180
        goto out;
2181
    }
2182

2183
    if (glusterd_find_snap_by_name(snapname)) {
2184
        ret = -1;
2185
        snprintf(err_str, sizeof(err_str),
2186
                 "Snapshot %s already "
2187
                 "exists",
2188
                 snapname);
2189
        *op_errno = EG_SNAPEXST;
2190
        goto out;
2191
    }
2192

2193
    for (i = 1; i <= volcount; i++) {
2194
        keylen = snprintf(key, sizeof(key), "volname%" PRId64, i);
2195
        ret = dict_get_strn(dict, key, keylen, &volname);
2196
        if (ret) {
2197
            snprintf(err_str, sizeof(err_str), "failed to get volume name");
2198
            goto out;
2199
        }
2200
        ret = glusterd_volinfo_find(volname, &volinfo);
2201
        if (ret) {
2202
            snprintf(err_str, sizeof(err_str), "Volume (%s) does not exist ",
2203
                     volname);
2204
            *op_errno = EG_NOVOL;
2205
            goto out;
2206
        }
2207

2208
        ret = -1;
2209
        if (!glusterd_is_volume_started(volinfo)) {
2210
            snprintf(err_str, sizeof(err_str),
2211
                     "volume %s is "
2212
                     "not started",
2213
                     volinfo->volname);
2214
            loglevel = GF_LOG_WARNING;
2215
            *op_errno = EG_VOLSTP;
2216
            goto out;
2217
        }
2218

2219
        if (glusterd_is_defrag_on(volinfo)) {
2220
            snprintf(err_str, sizeof(err_str),
2221
                     "rebalance process is running for the "
2222
                     "volume %s",
2223
                     volname);
2224
            loglevel = GF_LOG_WARNING;
2225
            *op_errno = EG_RBALRUN;
2226
            goto out;
2227
        }
2228

2229
        if (gd_vol_is_geo_rep_active(volinfo)) {
2230
            snprintf(err_str, sizeof(err_str),
2231
                     "geo-replication session is running for "
2232
                     "the volume %s. Session needs to be "
2233
                     "stopped before taking a snapshot.",
2234
                     volname);
2235
            loglevel = GF_LOG_WARNING;
2236
            *op_errno = EG_GEOREPRUN;
2237
            goto out;
2238
        }
2239

2240
        if (volinfo->is_snap_volume == _gf_true) {
2241
            snprintf(err_str, sizeof(err_str), "Volume %s is a snap volume",
2242
                     volname);
2243
            loglevel = GF_LOG_WARNING;
2244
            *op_errno = EG_ISSNAP;
2245
            goto out;
2246
        }
2247

2248
        /* "snap-max-hard-limit" might not be set by user explicitly,
2249
         * in that case it's better to consider the default value.
2250
         * Hence not erroring out if Key is not found.
2251
         */
2252
        ret = dict_get_uint64(
2253
            conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, &opt_hard_max);
2254
        if (ret) {
2255
            ret = 0;
2256
            gf_msg_debug(this->name, 0,
2257
                         "%s is not present "
2258
                         "in opts dictionary",
2259
                         GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
2260
        }
2261

2262
        if (volinfo->snap_max_hard_limit < opt_hard_max)
2263
            effective_max_limit = volinfo->snap_max_hard_limit;
2264
        else
2265
            effective_max_limit = opt_hard_max;
2266

2267
        if (volinfo->snap_count >= effective_max_limit) {
2268
            ret = -1;
2269
            snprintf(err_str, sizeof(err_str),
2270
                     "The number of existing snaps has reached "
2271
                     "the effective maximum limit of %" PRIu64
2272
                     ", "
2273
                     "for the volume (%s). Please delete few "
2274
                     "snapshots before taking further snapshots.",
2275
                     effective_max_limit, volname);
2276
            loglevel = GF_LOG_WARNING;
2277
            *op_errno = EG_HRDLMT;
2278
            goto out;
2279
        }
2280

2281
        snprintf(key, sizeof(key), "vol%" PRId64 "_volid", i);
2282
        ret = dict_get_bin(dict, key, (void **)&snap_volid);
2283
        if (ret) {
2284
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2285
                   "Unable to fetch snap_volid");
2286
            goto out;
2287
        }
2288

2289
        /* snap volume uuid is used as snapshot name.
2290
           This will avoid restrictions on snapshot names
2291
           provided by user */
2292
        GLUSTERD_GET_UUID_NOHYPHEN(snap_volname, *snap_volid);
2293

2294
        ret = glusterd_snap_create_clone_common_prevalidate(
2295
            rsp_dict, flags, snapname, err_str, snap_volname, i, volinfo,
2296
            &loglevel, 0, op_errno);
2297
        if (ret) {
2298
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PRE_VALIDATION_FAIL,
2299
                   "Failed to pre validate");
2300
            goto out;
2301
        }
2302
    }
2303

2304
    ret = dict_set_int64(rsp_dict, "volcount", volcount);
2305
    if (ret) {
2306
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2307
               "Failed to set volcount");
2308
        goto out;
2309
    }
2310

2311
    ret = 0;
2312

2313
out:
2314
    if (ret && err_str[0] != '\0') {
2315
        gf_msg(this->name, loglevel, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
2316
               err_str);
2317
        *op_errstr = gf_strdup(err_str);
2318
    }
2319

2320
    gf_msg_trace(this->name, 0, "Returning %d", ret);
2321
    return ret;
2322
}
2323

2324
glusterd_snap_t *
2325
glusterd_new_snap_object(void)
2326
{
2327
    glusterd_snap_t *snap = NULL;
2328

2329
    snap = GF_CALLOC(1, sizeof(*snap), gf_gld_mt_snap_t);
2330

2331
    if (snap) {
2332
        if (LOCK_INIT(&snap->lock)) {
2333
            gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_LOCK_INIT_FAILED,
2334
                   "Failed initiating"
2335
                   " snap lock");
2336
            GF_FREE(snap);
2337
            return NULL;
2338
        }
2339

2340
        CDS_INIT_LIST_HEAD(&snap->snap_list);
2341
        CDS_INIT_LIST_HEAD(&snap->volumes);
2342
        snap->snapname[0] = 0;
2343
        snap->snap_status = GD_SNAP_STATUS_INIT;
2344
    }
2345

2346
    return snap;
2347
};
2348

2349
/* Function glusterd_list_add_snapvol adds the volinfo object (snapshot volume)
2350
   to the snapshot object list and to the parent volume list */
2351
int32_t
2352
glusterd_list_add_snapvol(glusterd_volinfo_t *origin_vol,
2353
                          glusterd_volinfo_t *snap_vol)
2354
{
2355
    int ret = -1;
2356
    glusterd_snap_t *snap = NULL;
2357

2358
    GF_VALIDATE_OR_GOTO("glusterd", origin_vol, out);
2359
    GF_VALIDATE_OR_GOTO("glusterd", snap_vol, out);
2360

2361
    snap = snap_vol->snapshot;
2362
    GF_ASSERT(snap);
2363

2364
    cds_list_add_tail(&snap_vol->vol_list, &snap->volumes);
2365
    LOCK(&origin_vol->lock);
2366
    {
2367
        glusterd_list_add_order(&snap_vol->snapvol_list,
2368
                                &origin_vol->snap_volumes,
2369
                                glusterd_compare_snap_vol_time);
2370

2371
        origin_vol->snap_count++;
2372
    }
2373
    UNLOCK(&origin_vol->lock);
2374

2375
    gf_msg_debug(THIS->name, 0, "Snapshot %s added to the list",
2376
                 snap->snapname);
2377
    ret = 0;
2378
out:
2379
    return ret;
2380
}
2381

2382
glusterd_snap_t *
2383
glusterd_find_snap_by_name(char *snapname)
2384
{
2385
    glusterd_snap_t *snap = NULL;
2386
    glusterd_conf_t *priv = NULL;
2387

2388
    priv = THIS->private;
2389
    GF_ASSERT(priv);
2390
    GF_ASSERT(snapname);
2391

2392
    cds_list_for_each_entry(snap, &priv->snapshots, snap_list)
2393
    {
2394
        if (!strcmp(snap->snapname, snapname)) {
2395
            gf_msg_debug(THIS->name, 0,
2396
                         "Found "
2397
                         "snap %s (%s)",
2398
                         snap->snapname, uuid_utoa(snap->snap_id));
2399
            goto out;
2400
        }
2401
    }
2402
    snap = NULL;
2403
out:
2404
    return snap;
2405
}
2406

2407
glusterd_snap_t *
2408
glusterd_find_snap_by_id(uuid_t snap_id)
2409
{
2410
    glusterd_snap_t *snap = NULL;
2411
    glusterd_conf_t *priv = NULL;
2412

2413
    priv = THIS->private;
2414
    GF_ASSERT(priv);
2415

2416
    if (gf_uuid_is_null(snap_id))
2417
        goto out;
2418

2419
    cds_list_for_each_entry(snap, &priv->snapshots, snap_list)
2420
    {
2421
        if (!gf_uuid_compare(snap->snap_id, snap_id)) {
2422
            gf_msg_debug(THIS->name, 0,
2423
                         "Found "
2424
                         "snap %s (%s)",
2425
                         snap->snapname, uuid_utoa(snap->snap_id));
2426
            goto out;
2427
        }
2428
    }
2429
    snap = NULL;
2430
out:
2431
    return snap;
2432
}
2433

2434
int
2435
glusterd_snapshot_umount(glusterd_volinfo_t *snap_vol,
2436
                         glusterd_brickinfo_t *brickinfo, int32_t brick_count)
2437
{
2438
    int ret = -1;
2439
    int retry_count = 0;
2440
    glusterd_conf_t *priv = NULL;
2441
    char pidfile[PATH_MAX] = {
2442
        0,
2443
    };
2444
    pid_t pid = -1;
2445
    gf_boolean_t unmount = _gf_true;
2446
    char *mnt_pt = NULL;
2447
    xlator_t *this = NULL;
2448
    char snap_volume_id[GD_VOLUME_NAME_MAX] = "";
2449
    struct glusterd_snap_ops *snap_ops = NULL;
2450

2451
    this = THIS;
2452
    GF_ASSERT(this);
2453
    priv = this->private;
2454
    GF_ASSERT(priv);
2455

2456
    GF_ASSERT(brickinfo);
2457
    GF_ASSERT(snap_vol);
2458

2459
    GLUSTERD_GET_BRICK_PIDFILE(pidfile, snap_vol, brickinfo, priv);
2460
    if (gf_is_service_running(pidfile, &pid)) {
2461
        (void)send_attach_req(this, brickinfo->rpc, brickinfo->path, NULL, NULL,
2462
                              GLUSTERD_BRICK_TERMINATE, _gf_false);
2463
        brickinfo->status = GF_BRICK_STOPPED;
2464
    }
2465

2466
    /* Check if the brick is mounted and then try unmounting the brick */
2467
    ret = glusterd_get_brick_root(brickinfo->path, &mnt_pt);
2468
    if (ret) {
2469
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICK_PATH_UNMOUNTED,
2470
               "Getting the root "
2471
               "of the brick %s for volume %s (snap %s)"
2472
               "failed.",
2473
               brickinfo->origin_path, snap_vol->volname,
2474
               snap_vol->snapshot->snapname);
2475
        /* The brick path is already unmounted. Remove the lv only *
2476
         * Need not fail the operation */
2477
        ret = 0;
2478
        unmount = _gf_false;
2479
    }
2480

2481
    glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
2482

2483
    /* umount cannot be done when the brick process is still in the process
2484
       of shutdown, so give three re-tries */
2485
    while ((unmount == _gf_true) && (retry_count < 3)) {
2486
        retry_count++;
2487
        GLUSTERD_GET_UUID_NOHYPHEN(snap_volume_id, snap_vol->volume_id);
2488
        ret = snap_ops->deactivate(brickinfo, snap_vol->snapshot->snapname,
2489
                                   snap_volume_id, brick_count);
2490
        if (!ret)
2491
            break;
2492

2493
        gf_msg_debug(this->name, 0,
2494
                     "umount failed for "
2495
                     "path %s (brick: %s): %s. Retry(%d)",
2496
                     mnt_pt, brickinfo->path, strerror(errno), retry_count);
2497

2498
        /*
2499
         * This used to be one second, but that wasn't long enough
2500
         * to get past the spurious EPERM errors that prevent some
2501
         * tests (especially bug-1162462.t) from passing reliably.
2502
         *
2503
         * TBD: figure out where that garbage is coming from
2504
         */
2505
        sleep(3);
2506
    }
2507
    if (ret) {
2508
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNOUNT_FAILED,
2509
               "umount failed for "
2510
               "path %s (brick: %s): %s.",
2511
               mnt_pt, brickinfo->path, strerror(errno));
2512
        /*
2513
         * This is cheating, but necessary until we figure out how to
2514
         * shut down a brick within a still-living brick daemon so that
2515
         * random translators aren't keeping the mountpoint alive.
2516
         *
2517
         * TBD: figure out a real solution
2518
         */
2519
        ret = 0;
2520
    }
2521

2522
    return ret;
2523
}
2524

2525
int32_t
2526
glusterd_snapshot_remove(dict_t *rsp_dict, glusterd_volinfo_t *snap_vol,
2527
                         glusterd_brickinfo_t *brickinfo, int32_t brick_count)
2528
{
2529
    int32_t ret = -1;
2530
    xlator_t *this = NULL;
2531
    struct stat stbuf = {
2532
        0,
2533
    };
2534
    struct glusterd_snap_ops *snap_ops = NULL;
2535
    char snap_path[4352] = "";
2536

2537
    this = THIS;
2538
    GF_ASSERT(this);
2539
    GF_ASSERT(snap_vol);
2540
    GF_ASSERT(brickinfo);
2541

2542
    if ((snap_vol->is_snap_volume == _gf_false) &&
2543
        (gf_uuid_is_null(snap_vol->restored_from_snap))) {
2544
        gf_msg_debug(this->name, 0,
2545
                     "Not a snap volume, or a restored snap volume.");
2546
        ret = 0;
2547
        goto out;
2548
    }
2549

2550
    /* As deactivated snapshot have no active mount point we
2551
     * check only for activated snapshot.
2552
     */
2553
    if (snap_vol->status == GLUSTERD_STATUS_STARTED) {
2554
        ret = sys_lstat(brickinfo->path, &stbuf);
2555
        if (ret) {
2556
            gf_msg_debug(this->name, 0, "Brick %s:%s already deleted.",
2557
                         brickinfo->hostname, brickinfo->path);
2558
            ret = 0;
2559
            goto out;
2560
        }
2561
    }
2562

2563
    if (brickinfo->snap_status == -1) {
2564
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_SNAPSHOT_PENDING,
2565
               "snapshot was pending. snapshot supports "
2566
               "not present for brick %s:%s of the snap "
2567
               "%s.",
2568
               brickinfo->hostname, brickinfo->path,
2569
               snap_vol->snapshot->snapname);
2570

2571
        if (rsp_dict && (snap_vol->is_snap_volume == _gf_true)) {
2572
            /* Adding missed delete to the dict */
2573
            ret = glusterd_add_missed_snaps_to_dict(rsp_dict, snap_vol,
2574
                                                    brickinfo, brick_count + 1,
2575
                                                    GF_SNAP_OPTION_TYPE_DELETE);
2576
            if (ret) {
2577
                gf_msg(this->name, GF_LOG_ERROR, 0,
2578
                       GD_MSG_MISSED_SNAP_CREATE_FAIL,
2579
                       "Failed to add missed snapshot "
2580
                       "info for %s:%s in the "
2581
                       "rsp_dict",
2582
                       brickinfo->hostname, brickinfo->path);
2583
                goto out;
2584
            }
2585
        }
2586
        goto out;
2587
    }
2588

2589
    ret = glusterd_snapshot_umount(snap_vol, brickinfo, brick_count);
2590
    if (ret) {
2591
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
2592
               "Can not remove snapshot %s (%s) from "
2593
               "volume which does not support snapshots.",
2594
               brickinfo->path, snap_vol->snapshot->snapname);
2595
        ret = -1;
2596
        goto out;
2597
    }
2598

2599
    glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
2600
    ret = snap_ops->remove(brickinfo, snap_vol->snapshot->snapname,
2601
                           snap_vol->volname, brick_count);
2602
    if (ret) {
2603
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
2604
               "Failed to "
2605
               "remove the snapshot %s (%s)",
2606
               brickinfo->path, snap_vol->snapshot->snapname);
2607
    }
2608

2609
    /* Cleanup of Snapshot pid directory */
2610
    snprintf(snap_path, sizeof(snap_path), "%s/%s/%s", snap_mount_dir,
2611
             snap_vol->snapshot->snapname, snap_vol->volname);
2612
    ret = sys_rmdir(snap_path);
2613
    if (ret) {
2614
        /* Do not fail the Snapshot delete since
2615
          this is a cleanup operation. */
2616
        ret = 0;
2617
        /* If multiple bricks in same node(Same Volume/Snashot) then
2618
          this directory may contain pid file of that brick */
2619
        if (errno == ENOENT || errno == ENOTEMPTY)
2620
            gf_msg_debug(this->name, 0,
2621
                         "Failed to remove "
2622
                         "%s directory : error : %s",
2623
                         snap_path, strerror(errno));
2624
        else
2625
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
2626
                   "Failed to remove "
2627
                   "%s directory : error : %s",
2628
                   snap_path, strerror(errno));
2629
    }
2630

2631
    snprintf(snap_path, sizeof(snap_path), "%s/%s", snap_mount_dir,
2632
             snap_vol->snapshot->snapname);
2633
    ret = sys_rmdir(snap_path);
2634
    if (ret) {
2635
        /* Do not fail the Snapshot delete since
2636
          this is a cleanup operation. */
2637
        ret = 0;
2638
        if (errno == ENOENT || errno == ENOTEMPTY)
2639
            gf_msg_debug(this->name, 0,
2640
                         "Failed to remove "
2641
                         "%s directory : error : %s",
2642
                         snap_path, strerror(errno));
2643
        else
2644
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
2645
                   "Failed to remove "
2646
                   "%s directory : error : %s",
2647
                   snap_path, strerror(errno));
2648
    }
2649
out:
2650
    gf_msg_trace(this->name, 0, "Returning %d", ret);
2651
    return ret;
2652
}
2653

2654
int32_t
2655
glusterd_snap_volume_remove(dict_t *rsp_dict, glusterd_volinfo_t *snap_vol,
2656
                            gf_boolean_t remove_snapshot, gf_boolean_t force)
2657
{
2658
    int ret = -1;
2659
    int save_ret = 0;
2660
    glusterd_brickinfo_t *brickinfo = NULL;
2661
    glusterd_volinfo_t *origin_vol = NULL;
2662
    xlator_t *this = THIS;
2663
    int32_t brick_count = -1;
2664

2665
    GF_ASSERT(rsp_dict);
2666
    GF_ASSERT(snap_vol);
2667

2668
    if (!snap_vol) {
2669
        gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
2670
               "snap_vol in NULL");
2671
        ret = -1;
2672
        goto out;
2673
    }
2674

2675
    cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
2676
    {
2677
        brick_count++;
2678
        if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
2679
            continue;
2680

2681
        ret = glusterd_brick_stop(snap_vol, brickinfo, _gf_false);
2682
        if (ret) {
2683
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICK_STOP_FAIL,
2684
                   "Failed to stop "
2685
                   "brick for volume %s",
2686
                   snap_vol->volname);
2687
            save_ret = ret;
2688

2689
            /* Don't clean up the snap on error when
2690
               force flag is disabled */
2691
            if (!force)
2692
                goto out;
2693
        }
2694

2695
        /* Only remove the backend snapshot when required */
2696
        if (remove_snapshot) {
2697
            ret = glusterd_snapshot_remove(rsp_dict, snap_vol, brickinfo,
2698
                                           brick_count);
2699
            if (ret) {
2700
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2701
                       "Failed to remove "
2702
                       "snapshot volume %s",
2703
                       snap_vol->volname);
2704
                save_ret = ret;
2705
                if (!force)
2706
                    goto out;
2707
            }
2708
        }
2709
    }
2710

2711
    ret = glusterd_store_delete_volume(snap_vol);
2712
    if (ret) {
2713
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOL_DELETE_FAIL,
2714
               "Failed to remove volume %s "
2715
               "from store",
2716
               snap_vol->volname);
2717
        save_ret = ret;
2718
        if (!force)
2719
            goto out;
2720
    }
2721

2722
    if (!cds_list_empty(&snap_vol->snapvol_list)) {
2723
        ret = glusterd_volinfo_find(snap_vol->parent_volname, &origin_vol);
2724
        if (ret) {
2725
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
2726
                   "Failed to get "
2727
                   "parent volinfo %s  for volume  %s",
2728
                   snap_vol->parent_volname, snap_vol->volname);
2729
            save_ret = ret;
2730
            if (!force)
2731
                goto out;
2732
        }
2733
        origin_vol->snap_count--;
2734
    }
2735

2736
    glusterd_volinfo_unref(snap_vol);
2737

2738
    if (save_ret)
2739
        ret = save_ret;
2740
out:
2741
    gf_msg_trace(this->name, 0, "returning %d", ret);
2742
    return ret;
2743
}
2744

2745
int32_t
2746
glusterd_snap_remove(dict_t *rsp_dict, glusterd_snap_t *snap,
2747
                     gf_boolean_t remove_snapshot, gf_boolean_t force,
2748
                     gf_boolean_t is_clone)
2749
{
2750
    int ret = -1;
2751
    int save_ret = 0;
2752
    glusterd_volinfo_t *snap_vol = NULL;
2753
    glusterd_volinfo_t *tmp = NULL;
2754
    xlator_t *this = THIS;
2755

2756
    GF_ASSERT(rsp_dict);
2757
    GF_ASSERT(snap);
2758

2759
    if (!snap) {
2760
        gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
2761
               "snap is NULL");
2762
        ret = -1;
2763
        goto out;
2764
    }
2765

2766
    cds_list_for_each_entry_safe(snap_vol, tmp, &snap->volumes, vol_list)
2767
    {
2768
        ret = glusterd_snap_volume_remove(rsp_dict, snap_vol, remove_snapshot,
2769
                                          force);
2770
        if (ret && !force) {
2771
            /* Don't clean up the snap on error when
2772
               force flag is disabled */
2773
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2774
                   "Failed to remove "
2775
                   "volinfo %s for snap %s",
2776
                   snap_vol->volname, snap->snapname);
2777
            save_ret = ret;
2778
            goto out;
2779
        }
2780
    }
2781

2782
    /* A clone does not persist snap info in /var/lib/glusterd/snaps/ *
2783
     * and hence there is no snap info to be deleted from there       *
2784
     */
2785
    if (!is_clone) {
2786
        ret = glusterd_store_delete_snap(snap);
2787
        if (ret) {
2788
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2789
                   "Failed to remove snap %s from store", snap->snapname);
2790
            save_ret = ret;
2791
            if (!force)
2792
                goto out;
2793
        }
2794
    }
2795

2796
    ret = glusterd_snapobject_delete(snap);
2797
    if (ret)
2798
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2799
               "Failed to delete "
2800
               "snap object %s",
2801
               snap->snapname);
2802

2803
    if (save_ret)
2804
        ret = save_ret;
2805
out:
2806
    gf_msg_trace(THIS->name, 0, "returning %d", ret);
2807
    return ret;
2808
}
2809

2810
static int
2811
glusterd_snapshot_get_snapvol_detail(dict_t *dict, glusterd_volinfo_t *snap_vol,
2812
                                     const char *keyprefix, const int detail)
2813
{
2814
    int ret = -1;
2815
    int snap_limit = 0;
2816
    char key[64] = ""; /* keyprefix is quite small, up to 32 byts */
2817
    int keylen;
2818
    char *value = NULL;
2819
    glusterd_volinfo_t *origin_vol = NULL;
2820
    glusterd_conf_t *conf = NULL;
2821
    xlator_t *this = THIS;
2822
    uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
2823

2824
    conf = this->private;
2825
    GF_ASSERT(conf);
2826

2827
    GF_ASSERT(dict);
2828
    GF_ASSERT(snap_vol);
2829
    GF_ASSERT(keyprefix);
2830

2831
    /* Volume Name */
2832
    value = gf_strdup(snap_vol->volname);
2833
    if (!value)
2834
        goto out;
2835

2836
    keylen = snprintf(key, sizeof(key), "%s.volname", keyprefix);
2837
    ret = dict_set_dynstrn(dict, key, keylen, value);
2838
    if (ret) {
2839
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2840
               "Failed to set "
2841
               "volume name in dictionary: %s",
2842
               key);
2843
        goto out;
2844
    }
2845

2846
    /* Volume ID */
2847
    value = gf_strdup(uuid_utoa(snap_vol->volume_id));
2848
    if (NULL == value) {
2849
        ret = -1;
2850
        goto out;
2851
    }
2852

2853
    keylen = snprintf(key, sizeof(key), "%s.vol-id", keyprefix);
2854
    ret = dict_set_dynstrn(dict, key, keylen, value);
2855
    if (ret) {
2856
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_MEMORY,
2857
               "Failed to set "
2858
               "volume id in dictionary: %s",
2859
               key);
2860
        goto out;
2861
    }
2862
    value = NULL;
2863

2864
    /* volume status */
2865
    keylen = snprintf(key, sizeof(key), "%s.vol-status", keyprefix);
2866
    switch (snap_vol->status) {
2867
        case GLUSTERD_STATUS_STARTED:
2868
            ret = dict_set_nstrn(dict, key, keylen, "Started", SLEN("Started"));
2869
            break;
2870
        case GLUSTERD_STATUS_STOPPED:
2871
            ret = dict_set_nstrn(dict, key, keylen, "Stopped", SLEN("Stopped"));
2872
            break;
2873
        case GD_SNAP_STATUS_NONE:
2874
            ret = dict_set_nstrn(dict, key, keylen, "None", SLEN("None"));
2875
            break;
2876
        default:
2877
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
2878
                   "Invalid volume status");
2879
            ret = -1;
2880
            goto out;
2881
    }
2882
    if (ret) {
2883
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2884
               "Failed to set volume status"
2885
               " in dictionary: %s",
2886
               key);
2887
        goto out;
2888
    }
2889

2890
    ret = glusterd_volinfo_find(snap_vol->parent_volname, &origin_vol);
2891
    if (ret) {
2892
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
2893
               "failed to get the parent "
2894
               "volinfo for the volume %s",
2895
               snap_vol->volname);
2896
        goto out;
2897
    }
2898

2899
    /* "snap-max-hard-limit" might not be set by user explicitly,
2900
     * in that case it's better to consider the default value.
2901
     * Hence not erroring out if Key is not found.
2902
     */
2903
    ret = dict_get_uint64(conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
2904
                          &opt_hard_max);
2905
    if (ret) {
2906
        ret = 0;
2907
        gf_msg_debug(this->name, 0,
2908
                     "%s is not present in "
2909
                     "opts dictionary",
2910
                     GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
2911
    }
2912

2913
    if (opt_hard_max < origin_vol->snap_max_hard_limit) {
2914
        snap_limit = opt_hard_max;
2915
        gf_msg_debug(this->name, 0,
2916
                     "system snap-max-hard-limit is"
2917
                     " lesser than volume snap-max-hard-limit, "
2918
                     "snap-max-hard-limit value is set to %d",
2919
                     snap_limit);
2920
    } else {
2921
        snap_limit = origin_vol->snap_max_hard_limit;
2922
        gf_msg_debug(this->name, 0,
2923
                     "volume snap-max-hard-limit is"
2924
                     " lesser than system snap-max-hard-limit, "
2925
                     "snap-max-hard-limit value is set to %d",
2926
                     snap_limit);
2927
    }
2928

2929
    keylen = snprintf(key, sizeof(key), "%s.snaps-available", keyprefix);
2930
    if (snap_limit > origin_vol->snap_count)
2931
        ret = dict_set_int32n(dict, key, keylen,
2932
                              snap_limit - origin_vol->snap_count);
2933
    else
2934
        ret = dict_set_int32(dict, key, 0);
2935
    if (ret) {
2936
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2937
               "Failed to set available snaps");
2938
        goto out;
2939
    }
2940

2941
    keylen = snprintf(key, sizeof(key), "%s.snapcount", keyprefix);
2942
    ret = dict_set_int32n(dict, key, keylen, origin_vol->snap_count);
2943
    if (ret) {
2944
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2945
               "Could not save snapcount");
2946
        goto out;
2947
    }
2948

2949
    if (!detail)
2950
        goto out;
2951

2952
    /* Parent volume name */
2953
    value = gf_strdup(snap_vol->parent_volname);
2954
    if (!value)
2955
        goto out;
2956

2957
    keylen = snprintf(key, sizeof(key), "%s.origin-volname", keyprefix);
2958
    ret = dict_set_dynstrn(dict, key, keylen, value);
2959
    if (ret) {
2960
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2961
               "Failed to set parent "
2962
               "volume name in dictionary: %s",
2963
               key);
2964
        goto out;
2965
    }
2966
    value = NULL;
2967

2968
    ret = 0;
2969
out:
2970
    if (value)
2971
        GF_FREE(value);
2972

2973
    return ret;
2974
}
2975

2976
static int
2977
glusterd_snapshot_get_snap_detail(dict_t *dict, glusterd_snap_t *snap,
2978
                                  const char *keyprefix,
2979
                                  glusterd_volinfo_t *volinfo)
2980
{
2981
    int ret = -1;
2982
    int volcount = 0;
2983
    char key[32] = ""; /* keyprefix is quite small, up to 16 bytes */
2984
    int keylen;
2985
    char timestr[GF_TIMESTR_SIZE] = "";
2986
    char *value = NULL;
2987
    glusterd_volinfo_t *snap_vol = NULL;
2988
    glusterd_volinfo_t *tmp_vol = NULL;
2989
    xlator_t *this = THIS;
2990

2991
    GF_ASSERT(dict);
2992
    GF_ASSERT(snap);
2993
    GF_ASSERT(keyprefix);
2994

2995
    /* Snap Name */
2996
    value = gf_strdup(snap->snapname);
2997
    if (!value)
2998
        goto out;
2999

3000
    keylen = snprintf(key, sizeof(key), "%s.snapname", keyprefix);
3001
    ret = dict_set_dynstrn(dict, key, keylen, value);
3002
    if (ret) {
3003
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3004
               "Failed to set "
3005
               "snap name in dictionary");
3006
        goto out;
3007
    }
3008

3009
    /* Snap ID */
3010
    value = gf_strdup(uuid_utoa(snap->snap_id));
3011
    if (NULL == value) {
3012
        ret = -1;
3013
        goto out;
3014
    }
3015

3016
    keylen = snprintf(key, sizeof(key), "%s.snap-id", keyprefix);
3017
    ret = dict_set_dynstrn(dict, key, keylen, value);
3018
    if (ret) {
3019
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3020
               "Failed to set "
3021
               "snap id in dictionary");
3022
        goto out;
3023
    }
3024
    value = NULL;
3025

3026
    gf_time_fmt_FT(timestr, sizeof timestr, snap->time_stamp);
3027
    value = gf_strdup(timestr);
3028

3029
    if (NULL == value) {
3030
        ret = -1;
3031
        goto out;
3032
    }
3033

3034
    keylen = snprintf(key, sizeof(key), "%s.snap-time", keyprefix);
3035
    ret = dict_set_dynstrn(dict, key, keylen, value);
3036
    if (ret) {
3037
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3038
               "Failed to set "
3039
               "snap time stamp in dictionary");
3040
        goto out;
3041
    }
3042
    value = NULL;
3043

3044
    /* If snap description is provided then add that into dictionary */
3045
    if (NULL != snap->description) {
3046
        value = gf_strdup(snap->description);
3047
        if (NULL == value) {
3048
            ret = -1;
3049
            goto out;
3050
        }
3051

3052
        keylen = snprintf(key, sizeof(key), "%s.snap-desc", keyprefix);
3053
        ret = dict_set_dynstrn(dict, key, keylen, value);
3054
        if (ret) {
3055
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3056
                   "Failed to set "
3057
                   "snap description in dictionary");
3058
            goto out;
3059
        }
3060
        value = NULL;
3061
    }
3062

3063
    keylen = snprintf(key, sizeof(key), "%s.snap-status", keyprefix);
3064
    switch (snap->snap_status) {
3065
        case GD_SNAP_STATUS_INIT:
3066
            ret = dict_set_nstrn(dict, key, keylen, "Init", SLEN("Init"));
3067
            break;
3068
        case GD_SNAP_STATUS_IN_USE:
3069
            ret = dict_set_nstrn(dict, key, keylen, "In-use", SLEN("In-use"));
3070
            break;
3071
        case GD_SNAP_STATUS_DECOMMISSION:
3072
            ret = dict_set_nstrn(dict, key, keylen, "Decommisioned",
3073
                                 SLEN("Decommisioned"));
3074
            break;
3075
        case GD_SNAP_STATUS_RESTORED:
3076
            ret = dict_set_nstrn(dict, key, keylen, "Restored",
3077
                                 SLEN("Restored"));
3078
            break;
3079
        case GD_SNAP_STATUS_NONE:
3080
            ret = dict_set_nstrn(dict, key, keylen, "None", SLEN("None"));
3081
            break;
3082
        default:
3083
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
3084
                   "Invalid snap status");
3085
            ret = -1;
3086
            goto out;
3087
    }
3088
    if (ret) {
3089
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3090
               "Failed to set snap status "
3091
               "in dictionary");
3092
        goto out;
3093
    }
3094

3095
    if (volinfo) {
3096
        volcount = 1;
3097
        snprintf(key, sizeof(key), "%s.vol%d", keyprefix, volcount);
3098
        ret = glusterd_snapshot_get_snapvol_detail(dict, volinfo, key, 0);
3099
        if (ret) {
3100
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_DICT_GET_FAILED,
3101
                   "Failed to "
3102
                   "get volume detail %s for snap %s",
3103
                   snap_vol->volname, snap->snapname);
3104
            goto out;
3105
        }
3106
        goto done;
3107
    }
3108

3109
    cds_list_for_each_entry_safe(snap_vol, tmp_vol, &snap->volumes, vol_list)
3110
    {
3111
        volcount++;
3112
        snprintf(key, sizeof(key), "%s.vol%d", keyprefix, volcount);
3113
        ret = glusterd_snapshot_get_snapvol_detail(dict, snap_vol, key, 1);
3114
        if (ret) {
3115
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3116
                   "Failed to "
3117
                   "get volume detail %s for snap %s",
3118
                   snap_vol->volname, snap->snapname);
3119
            goto out;
3120
        }
3121
    }
3122

3123
done:
3124
    keylen = snprintf(key, sizeof(key), "%s.vol-count", keyprefix);
3125
    ret = dict_set_int32n(dict, key, keylen, volcount);
3126
    if (ret) {
3127
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3128
               "Failed to set %s", key);
3129
        goto out;
3130
    }
3131

3132
    ret = 0;
3133
out:
3134
    if (value)
3135
        GF_FREE(value);
3136

3137
    return ret;
3138
}
3139

3140
static int
3141
glusterd_snapshot_get_all_snap_info(dict_t *dict)
3142
{
3143
    int ret = -1;
3144
    int snapcount = 0;
3145
    char key[16] = "";
3146
    glusterd_snap_t *snap = NULL;
3147
    glusterd_snap_t *tmp_snap = NULL;
3148
    glusterd_conf_t *priv = NULL;
3149
    xlator_t *this = THIS;
3150

3151
    priv = this->private;
3152
    GF_ASSERT(priv);
3153

3154
    /* General parameter validation */
3155
    GF_ASSERT(dict);
3156

3157
    cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
3158
    {
3159
        snapcount++;
3160
        snprintf(key, sizeof(key), "snap%d", snapcount);
3161
        ret = glusterd_snapshot_get_snap_detail(dict, snap, key, NULL);
3162
        if (ret) {
3163
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3164
                   "Failed to get "
3165
                   "snapdetail for snap %s",
3166
                   snap->snapname);
3167
            goto out;
3168
        }
3169
    }
3170

3171
    ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3172
    if (ret) {
3173
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3174
               "Failed to set snapcount");
3175
        goto out;
3176
    }
3177

3178
    ret = 0;
3179
out:
3180
    return ret;
3181
}
3182

3183
int
3184
glusterd_snapshot_get_info_by_volume(dict_t *dict, char *volname, char *err_str,
3185
                                     size_t len)
3186
{
3187
    int ret = -1;
3188
    int snapcount = 0;
3189
    int snap_limit = 0;
3190
    char *value = NULL;
3191
    char key[16] = "";
3192
    glusterd_volinfo_t *volinfo = NULL;
3193
    glusterd_volinfo_t *snap_vol = NULL;
3194
    glusterd_volinfo_t *tmp_vol = NULL;
3195
    glusterd_conf_t *conf = NULL;
3196
    xlator_t *this = THIS;
3197
    uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
3198

3199
    conf = this->private;
3200
    GF_ASSERT(conf);
3201

3202
    GF_ASSERT(dict);
3203
    GF_ASSERT(volname);
3204

3205
    ret = glusterd_volinfo_find(volname, &volinfo);
3206
    if (ret) {
3207
        snprintf(err_str, len, "Volume (%s) does not exist", volname);
3208
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND, "%s",
3209
               err_str);
3210
        goto out;
3211
    }
3212

3213
    /* "snap-max-hard-limit" might not be set by user explicitly,
3214
     * in that case it's better to consider the default value.
3215
     * Hence not erroring out if Key is not found.
3216
     */
3217
    ret = dict_get_uint64(conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
3218
                          &opt_hard_max);
3219
    if (ret) {
3220
        ret = 0;
3221
        gf_msg_debug(this->name, 0,
3222
                     "%s is not present in "
3223
                     "opts dictionary",
3224
                     GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
3225
    }
3226

3227
    if (opt_hard_max < volinfo->snap_max_hard_limit) {
3228
        snap_limit = opt_hard_max;
3229
        gf_msg_debug(this->name, 0,
3230
                     "system snap-max-hard-limit is"
3231
                     " lesser than volume snap-max-hard-limit, "
3232
                     "snap-max-hard-limit value is set to %d",
3233
                     snap_limit);
3234
    } else {
3235
        snap_limit = volinfo->snap_max_hard_limit;
3236
        gf_msg_debug(this->name, 0,
3237
                     "volume snap-max-hard-limit is"
3238
                     " lesser than system snap-max-hard-limit, "
3239
                     "snap-max-hard-limit value is set to %d",
3240
                     snap_limit);
3241
    }
3242

3243
    if (snap_limit > volinfo->snap_count)
3244
        ret = dict_set_int32_sizen(dict, "snaps-available",
3245
                                   snap_limit - volinfo->snap_count);
3246
    else
3247
        ret = dict_set_int32_sizen(dict, "snaps-available", 0);
3248
    if (ret) {
3249
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3250
               "Failed to set available snaps");
3251
        goto out;
3252
    }
3253

3254
    /* Origin volume name */
3255
    value = gf_strdup(volinfo->volname);
3256
    if (!value)
3257
        goto out;
3258

3259
    ret = dict_set_dynstr_sizen(dict, "origin-volname", value);
3260
    if (ret) {
3261
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3262
               "Failed to set parent "
3263
               "volume name in dictionary: %s",
3264
               value);
3265
        goto out;
3266
    }
3267
    value = NULL;
3268

3269
    cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
3270
                                 snapvol_list)
3271
    {
3272
        snapcount++;
3273
        snprintf(key, sizeof(key), "snap%d", snapcount);
3274
        ret = glusterd_snapshot_get_snap_detail(dict, snap_vol->snapshot, key,
3275
                                                snap_vol);
3276
        if (ret) {
3277
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3278
                   "Failed to get "
3279
                   "snapdetail for snap %s",
3280
                   snap_vol->snapshot->snapname);
3281
            goto out;
3282
        }
3283
    }
3284
    ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3285
    if (ret) {
3286
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3287
               "Failed to set snapcount");
3288
        goto out;
3289
    }
3290

3291
    ret = 0;
3292
out:
3293
    if (value)
3294
        GF_FREE(value);
3295

3296
    return ret;
3297
}
3298

3299
/* This function will be called from RPC handler routine.
3300
 * This function is responsible for getting the requested
3301
 * snapshot info into the dictionary.
3302
 *
3303
 * @param req   RPC request object. Required for sending a response back.
3304
 * @param op    glusterd operation. Required for sending a response back.
3305
 * @param dict  pointer to dictionary which will contain both
3306
 *              request and response key-pair values.
3307
 * @return -1 on error and 0 on success
3308
 */
3309
int
3310
glusterd_handle_snapshot_info(rpcsvc_request_t *req, glusterd_op_t op,
3311
                              dict_t *dict, char *err_str, size_t len)
3312
{
3313
    int ret = -1;
3314
    int8_t snap_driven = 1;
3315
    char *volname = NULL;
3316
    char *snapname = NULL;
3317
    glusterd_snap_t *snap = NULL;
3318
    xlator_t *this = THIS;
3319
    int32_t cmd = GF_SNAP_INFO_TYPE_ALL;
3320

3321
    GF_VALIDATE_OR_GOTO(this->name, req, out);
3322
    GF_VALIDATE_OR_GOTO(this->name, dict, out);
3323

3324
    ret = dict_get_int32(dict, "sub-cmd", &cmd);
3325
    if (ret) {
3326
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3327
               "Failed to get type "
3328
               "of snapshot info");
3329
        goto out;
3330
    }
3331

3332
    switch (cmd) {
3333
        case GF_SNAP_INFO_TYPE_ALL: {
3334
            ret = glusterd_snapshot_get_all_snap_info(dict);
3335
            if (ret) {
3336
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3337
                       "Failed to get info of all snaps");
3338
                goto out;
3339
            }
3340
            break;
3341
        }
3342

3343
        case GF_SNAP_INFO_TYPE_SNAP: {
3344
            ret = dict_get_str(dict, "snapname", &snapname);
3345
            if (ret) {
3346
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3347
                       "Failed to get snap name");
3348
                goto out;
3349
            }
3350

3351
            ret = dict_set_int32_sizen(dict, "snapcount", 1);
3352
            if (ret) {
3353
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3354
                       "Failed to set snapcount");
3355
                goto out;
3356
            }
3357

3358
            snap = glusterd_find_snap_by_name(snapname);
3359
            if (!snap) {
3360
                snprintf(err_str, len, "Snapshot (%s) does not exist",
3361
                         snapname);
3362
                gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
3363
                       "%s", err_str);
3364
                ret = -1;
3365
                goto out;
3366
            }
3367
            ret = glusterd_snapshot_get_snap_detail(dict, snap, "snap1", NULL);
3368
            if (ret) {
3369
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
3370
                       "Failed to get snap detail of snap "
3371
                       "%s",
3372
                       snap->snapname);
3373
                goto out;
3374
            }
3375
            break;
3376
        }
3377

3378
        case GF_SNAP_INFO_TYPE_VOL: {
3379
            ret = dict_get_str(dict, "volname", &volname);
3380
            if (ret) {
3381
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
3382
                       "Failed to get volname");
3383
                goto out;
3384
            }
3385
            ret = glusterd_snapshot_get_info_by_volume(dict, volname, err_str,
3386
                                                       len);
3387
            if (ret) {
3388
                gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
3389
                       "Failed to get volume info of volume "
3390
                       "%s",
3391
                       volname);
3392
                goto out;
3393
            }
3394
            snap_driven = 0;
3395
            break;
3396
        }
3397
    }
3398

3399
    ret = dict_set_int8(dict, "snap-driven", snap_driven);
3400
    if (ret) {
3401
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3402
               "Failed to set snap-driven");
3403
        goto out;
3404
    }
3405

3406
    /* If everything is successful then send the response back to cli.
3407
     * In case of failure the caller of this function will take care
3408
       of the response */
3409
    ret = glusterd_op_send_cli_response(op, 0, 0, req, dict, err_str);
3410
    if (ret) {
3411
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
3412
               "Failed to send cli "
3413
               "response");
3414
        goto out;
3415
    }
3416

3417
    ret = 0;
3418

3419
out:
3420
    return ret;
3421
}
3422

3423
/* This function sets all the snapshot names in the dictionary */
3424
int
3425
glusterd_snapshot_get_all_snapnames(dict_t *dict)
3426
{
3427
    int ret = -1;
3428
    int snapcount = 0;
3429
    char *snapname = NULL;
3430
    char key[64] = "";
3431
    int keylen;
3432
    glusterd_snap_t *snap = NULL;
3433
    glusterd_snap_t *tmp_snap = NULL;
3434
    glusterd_conf_t *priv = NULL;
3435
    xlator_t *this = THIS;
3436

3437
    priv = this->private;
3438
    GF_ASSERT(priv);
3439
    GF_ASSERT(dict);
3440

3441
    cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
3442
    {
3443
        snapcount++;
3444
        snapname = gf_strdup(snap->snapname);
3445
        if (!snapname) {
3446
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3447
                   "strdup failed");
3448
            ret = -1;
3449
            goto out;
3450
        }
3451
        keylen = snprintf(key, sizeof(key), "snapname%d", snapcount);
3452
        ret = dict_set_dynstrn(dict, key, keylen, snapname);
3453
        if (ret) {
3454
            GF_FREE(snapname);
3455
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3456
                   "Failed to set %s", key);
3457
            goto out;
3458
        }
3459
    }
3460

3461
    ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3462
    if (ret) {
3463
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3464
               "Failed to set snapcount");
3465
        goto out;
3466
    }
3467

3468
    ret = 0;
3469
out:
3470

3471
    return ret;
3472
}
3473

3474
/* This function sets all the snapshot names
3475
   under a given volume in the dictionary */
3476
int
3477
glusterd_snapshot_get_vol_snapnames(dict_t *dict, glusterd_volinfo_t *volinfo)
3478
{
3479
    int ret = -1;
3480
    int snapcount = 0;
3481
    char *snapname = NULL;
3482
    char key[32] = "";
3483
    glusterd_volinfo_t *snap_vol = NULL;
3484
    glusterd_volinfo_t *tmp_vol = NULL;
3485
    xlator_t *this = THIS;
3486

3487
    GF_ASSERT(dict);
3488
    GF_ASSERT(volinfo);
3489

3490
    cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
3491
                                 snapvol_list)
3492
    {
3493
        snapcount++;
3494
        snprintf(key, sizeof(key), "snapname%d", snapcount);
3495

3496
        ret = dict_set_dynstr_with_alloc(dict, key,
3497
                                         snap_vol->snapshot->snapname);
3498
        if (ret) {
3499
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3500
                   "Failed to "
3501
                   "set %s",
3502
                   key);
3503
            GF_FREE(snapname);
3504
            goto out;
3505
        }
3506
    }
3507

3508
    ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3509
    if (ret) {
3510
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3511
               "Failed to set snapcount");
3512
        goto out;
3513
    }
3514

3515
    ret = 0;
3516
out:
3517

3518
    return ret;
3519
}
3520

3521
int
3522
glusterd_handle_snapshot_list(rpcsvc_request_t *req, glusterd_op_t op,
3523
                              dict_t *dict, char *err_str, size_t len,
3524
                              uint32_t *op_errno)
3525
{
3526
    int ret = -1;
3527
    char *volname = NULL;
3528
    glusterd_volinfo_t *volinfo = NULL;
3529
    xlator_t *this = THIS;
3530

3531
    GF_VALIDATE_OR_GOTO(this->name, req, out);
3532
    GF_VALIDATE_OR_GOTO(this->name, dict, out);
3533
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
3534

3535
    /* Ignore error for getting volname as it is optional */
3536
    ret = dict_get_str(dict, "volname", &volname);
3537

3538
    if (NULL == volname) {
3539
        ret = glusterd_snapshot_get_all_snapnames(dict);
3540
        if (ret) {
3541
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_LIST_GET_FAIL,
3542
                   "Failed to get snapshot list");
3543
            goto out;
3544
        }
3545
    } else {
3546
        ret = glusterd_volinfo_find(volname, &volinfo);
3547
        if (ret) {
3548
            snprintf(err_str, len, "Volume (%s) does not exist", volname);
3549
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND, "%s",
3550
                   err_str);
3551
            *op_errno = EG_NOVOL;
3552
            goto out;
3553
        }
3554

3555
        ret = glusterd_snapshot_get_vol_snapnames(dict, volinfo);
3556
        if (ret) {
3557
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_LIST_GET_FAIL,
3558
                   "Failed to get snapshot list for volume %s", volname);
3559
            goto out;
3560
        }
3561
    }
3562

3563
    /* If everything is successful then send the response back to cli.
3564
    In case of failure the caller of this function will take of response.*/
3565
    ret = glusterd_op_send_cli_response(op, 0, 0, req, dict, err_str);
3566
    if (ret) {
3567
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
3568
               "Failed to send cli "
3569
               "response");
3570
        goto out;
3571
    }
3572

3573
    ret = 0;
3574

3575
out:
3576
    return ret;
3577
}
3578

3579
/* This is a snapshot create handler function. This function will be
3580
 * executed in the originator node. This function is responsible for
3581
 * calling mgmt_v3 framework to do the actual snap creation on all the
3582
 * bricks
3583
 *
3584
 * @param req           RPC request object
3585
 * @param op            gluster operation
3586
 * @param dict          dictionary containing snapshot restore request
3587
 * @param err_str       In case of an err this string should be populated
3588
 * @param len           length of err_str buffer
3589
 *
3590
 * @return              Negative value on Failure and 0 in success
3591
 */
3592
int
3593
glusterd_handle_snapshot_create(rpcsvc_request_t *req, glusterd_op_t op,
3594
                                dict_t *dict, char *err_str, size_t len)
3595
{
3596
    int ret = -1;
3597
    char *volname = NULL;
3598
    char *snapname = NULL;
3599
    int64_t volcount = 0;
3600
    xlator_t *this = THIS;
3601
    char key[64] = "";
3602
    int keylen;
3603
    char *username = NULL;
3604
    char *password = NULL;
3605
    uuid_t *uuid_ptr = NULL;
3606
    uuid_t tmp_uuid = {0};
3607
    int i = 0;
3608
    int timestamp = 0;
3609
    char snap_volname[GD_VOLUME_NAME_MAX] = "";
3610
    char new_snapname[GLUSTERD_MAX_SNAP_NAME] = "";
3611
    char gmt_snaptime[GLUSTERD_MAX_SNAP_NAME] = "";
3612
    time_t snap_time;
3613
    GF_ASSERT(req);
3614
    GF_ASSERT(dict);
3615
    GF_ASSERT(err_str);
3616

3617
    ret = dict_get_int64(dict, "volcount", &volcount);
3618
    if (ret) {
3619
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3620
               "failed to "
3621
               "get the volume count");
3622
        goto out;
3623
    }
3624
    if (volcount <= 0) {
3625
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
3626
               "Invalid volume count %" PRId64 " supplied", volcount);
3627
        ret = -1;
3628
        goto out;
3629
    }
3630

3631
    ret = dict_get_str(dict, "snapname", &snapname);
3632
    if (ret) {
3633
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3634
               "failed to get the snapname");
3635
        goto out;
3636
    }
3637

3638
    timestamp = dict_get_str_boolean(dict, "no-timestamp", _gf_false);
3639
    if (timestamp == -1) {
3640
        gf_log(this->name, GF_LOG_ERROR,
3641
               "Failed to get "
3642
               "no-timestamp flag ");
3643
        goto out;
3644
    }
3645

3646
    snap_time = gf_time();
3647
    ret = dict_set_int64(dict, "snap-time", (int64_t)snap_time);
3648
    if (ret) {
3649
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3650
               "Unable to set snap-time");
3651
        goto out;
3652
    }
3653

3654
    if (!timestamp) {
3655
        strftime(gmt_snaptime, sizeof(gmt_snaptime), "_GMT-%Y.%m.%d-%H.%M.%S",
3656
                 gmtime(&snap_time));
3657
        snprintf(new_snapname, sizeof(new_snapname), "%s%s", snapname,
3658
                 gmt_snaptime);
3659
        ret = dict_set_dynstr_with_alloc(dict, "snapname", new_snapname);
3660
        if (ret) {
3661
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3662
                   "Unable to update "
3663
                   "snap-name");
3664
            goto out;
3665
        }
3666
        snapname = new_snapname;
3667
    }
3668

3669
    if (strlen(snapname) >= GLUSTERD_MAX_SNAP_NAME) {
3670
        snprintf(err_str, len,
3671
                 "snapname cannot exceed 255 "
3672
                 "characters");
3673
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s",
3674
               err_str);
3675
        ret = -1;
3676
        goto out;
3677
    }
3678

3679
    uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3680
    if (!uuid_ptr) {
3681
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3682
               "Out Of Memory");
3683
        ret = -1;
3684
        goto out;
3685
    }
3686

3687
    gf_uuid_generate(*uuid_ptr);
3688
    ret = dict_set_bin(dict, "snap-id", uuid_ptr, sizeof(uuid_t));
3689
    if (ret) {
3690
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3691
               "Unable to set snap-id");
3692
        GF_FREE(uuid_ptr);
3693
        goto out;
3694
    }
3695
    uuid_ptr = NULL;
3696

3697
    for (i = 1; i <= volcount; i++) {
3698
        keylen = snprintf(key, sizeof(key), "volname%d", i);
3699
        ret = dict_get_strn(dict, key, keylen, &volname);
3700
        if (ret) {
3701
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3702
                   "Failed to get volume name");
3703
            goto out;
3704
        }
3705

3706
        /* generate internal username and password  for the snap*/
3707
        gf_uuid_generate(tmp_uuid);
3708
        username = gf_strdup(uuid_utoa(tmp_uuid));
3709
        keylen = snprintf(key, sizeof(key), "volume%d_username", i);
3710
        ret = dict_set_dynstrn(dict, key, keylen, username);
3711
        if (ret) {
3712
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3713
                   "Failed to set snap "
3714
                   "username for volume %s",
3715
                   volname);
3716
            GF_FREE(username);
3717
            goto out;
3718
        }
3719

3720
        gf_uuid_generate(tmp_uuid);
3721
        password = gf_strdup(uuid_utoa(tmp_uuid));
3722
        keylen = snprintf(key, sizeof(key), "volume%d_password", i);
3723
        ret = dict_set_dynstrn(dict, key, keylen, password);
3724
        if (ret) {
3725
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3726
                   "Failed to set snap "
3727
                   "password for volume %s",
3728
                   volname);
3729
            GF_FREE(password);
3730
            goto out;
3731
        }
3732

3733
        uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3734
        if (!uuid_ptr) {
3735
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3736
                   "Out Of Memory");
3737
            ret = -1;
3738
            goto out;
3739
        }
3740

3741
        snprintf(key, sizeof(key), "vol%d_volid", i);
3742
        gf_uuid_generate(*uuid_ptr);
3743
        ret = dict_set_bin(dict, key, uuid_ptr, sizeof(uuid_t));
3744
        if (ret) {
3745
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3746
                   "Unable to set snap_volid");
3747
            GF_FREE(uuid_ptr);
3748
            goto out;
3749
        }
3750
        GLUSTERD_GET_UUID_NOHYPHEN(snap_volname, *uuid_ptr);
3751
        snprintf(key, sizeof(key), "snap-volname%d", i);
3752
        ret = dict_set_dynstr_with_alloc(dict, key, snap_volname);
3753
        if (ret) {
3754
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3755
                   "Unable to set snap volname");
3756
            GF_FREE(uuid_ptr);
3757
            goto out;
3758
        }
3759
    }
3760

3761
    ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
3762
    if (ret) {
3763
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
3764
               "Failed to initiate snap "
3765
               "phases");
3766
    }
3767

3768
out:
3769
    return ret;
3770
}
3771

3772
/* This is a snapshot status handler function. This function will be
3773
 * executed in a originator node. This function is responsible for
3774
 * calling mgmt v3 framework to get the actual snapshot status from
3775
 * all the bricks
3776
 *
3777
 * @param req           RPC request object
3778
 * @param op            gluster operation
3779
 * @param dict          dictionary containing snapshot status request
3780
 * @param err_str       In case of an err this string should be populated
3781
 * @param len           length of err_str buffer
3782
 *
3783
 * return :  0  in case of success.
3784
 *          -1  in case of failure.
3785
 *
3786
 */
3787
int
3788
glusterd_handle_snapshot_status(rpcsvc_request_t *req, glusterd_op_t op,
3789
                                dict_t *dict, char *err_str, size_t len)
3790
{
3791
    int ret = -1;
3792

3793
    GF_ASSERT(req);
3794
    GF_ASSERT(dict);
3795
    GF_ASSERT(err_str);
3796

3797
    ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
3798
    if (ret) {
3799
        gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
3800
               "Failed to initiate "
3801
               "snap phases");
3802
        goto out;
3803
    }
3804

3805
    ret = 0;
3806
out:
3807
    return ret;
3808
}
3809

3810
/* This is a snapshot clone handler function. This function will be
3811
 * executed in the originator node. This function is responsible for
3812
 * calling mgmt_v3 framework to do the actual snap clone on all the bricks
3813
 *
3814
 * @param req           RPC request object
3815
 * @param op            gluster operation
3816
 * @param dict          dictionary containing snapshot restore request
3817
 * @param err_str       In case of an err this string should be populated
3818
 * @param len           length of err_str buffer
3819
 *
3820
 * @return              Negative value on Failure and 0 in success
3821
 */
3822
int
3823
glusterd_handle_snapshot_clone(rpcsvc_request_t *req, glusterd_op_t op,
3824
                               dict_t *dict, char *err_str, size_t len)
3825
{
3826
    int ret = -1;
3827
    char *clonename = NULL;
3828
    char *snapname = NULL;
3829
    xlator_t *this = THIS;
3830
    char key[64] = "";
3831
    int keylen;
3832
    char *username = NULL;
3833
    char *password = NULL;
3834
    char *volname = NULL;
3835
    uuid_t *uuid_ptr = NULL;
3836
    uuid_t tmp_uuid = {0};
3837
    int i = 0;
3838
    char snap_volname[GD_VOLUME_NAME_MAX] = "";
3839

3840
    GF_ASSERT(req);
3841
    GF_ASSERT(dict);
3842
    GF_ASSERT(err_str);
3843

3844
    ret = dict_get_str(dict, "clonename", &clonename);
3845
    if (ret) {
3846
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3847
               "failed to "
3848
               "get the clone name");
3849
        goto out;
3850
    }
3851
    /*We need to take a volume lock on clone name*/
3852
    volname = gf_strdup(clonename);
3853
    keylen = snprintf(key, sizeof(key), "volname1");
3854
    ret = dict_set_dynstrn(dict, key, keylen, volname);
3855
    if (ret) {
3856
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3857
               "Failed to set clone "
3858
               "name for volume locking");
3859
        GF_FREE(volname);
3860
        goto out;
3861
    }
3862

3863
    ret = dict_get_str(dict, "snapname", &snapname);
3864
    if (ret) {
3865
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3866
               "failed to get the snapname");
3867
        goto out;
3868
    }
3869

3870
    uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3871
    if (!uuid_ptr) {
3872
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3873
               "Out Of Memory");
3874
        ret = -1;
3875
        goto out;
3876
    }
3877

3878
    gf_uuid_generate(*uuid_ptr);
3879
    ret = dict_set_bin(dict, "clone-id", uuid_ptr, sizeof(uuid_t));
3880
    if (ret) {
3881
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3882
               "Unable to set clone-id");
3883
        GF_FREE(uuid_ptr);
3884
        goto out;
3885
    }
3886
    uuid_ptr = NULL;
3887

3888
    ret = dict_get_str(dict, "snapname", &snapname);
3889
    if (ret) {
3890
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3891
               "Failed to get snapname name");
3892
        goto out;
3893
    }
3894

3895
    gf_uuid_generate(tmp_uuid);
3896
    username = gf_strdup(uuid_utoa(tmp_uuid));
3897
    keylen = snprintf(key, sizeof(key), "volume1_username");
3898
    ret = dict_set_dynstrn(dict, key, keylen, username);
3899
    if (ret) {
3900
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3901
               "Failed to set clone "
3902
               "username for volume %s",
3903
               clonename);
3904
        GF_FREE(username);
3905
        goto out;
3906
    }
3907

3908
    gf_uuid_generate(tmp_uuid);
3909
    password = gf_strdup(uuid_utoa(tmp_uuid));
3910
    keylen = snprintf(key, sizeof(key), "volume1_password");
3911
    ret = dict_set_dynstrn(dict, key, keylen, password);
3912
    if (ret) {
3913
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3914
               "Failed to set clone "
3915
               "password for volume %s",
3916
               clonename);
3917
        GF_FREE(password);
3918
        goto out;
3919
    }
3920

3921
    uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3922
    if (!uuid_ptr) {
3923
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3924
               "Out Of Memory");
3925
        ret = -1;
3926
        goto out;
3927
    }
3928

3929
    snprintf(key, sizeof(key), "vol1_volid");
3930
    gf_uuid_generate(*uuid_ptr);
3931
    ret = dict_set_bin(dict, key, uuid_ptr, sizeof(uuid_t));
3932
    if (ret) {
3933
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3934
               "Unable to set clone_volid");
3935
        GF_FREE(uuid_ptr);
3936
        goto out;
3937
    }
3938
    snprintf(key, sizeof(key), "clone-volname%d", i);
3939
    ret = dict_set_dynstr_with_alloc(dict, key, snap_volname);
3940
    if (ret) {
3941
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3942
               "Unable to set snap volname");
3943
        GF_FREE(uuid_ptr);
3944
        goto out;
3945
    }
3946

3947
    ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
3948
    if (ret) {
3949
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
3950
               "Failed to initiate "
3951
               "snap phases");
3952
    }
3953

3954
out:
3955
    return ret;
3956
}
3957

3958
/* This is a snapshot restore handler function. This function will be
3959
 * executed in the originator node. This function is responsible for
3960
 * calling mgmt_v3 framework to do the actual restore on all the bricks
3961
 *
3962
 * @param req           RPC request object
3963
 * @param op            gluster operation
3964
 * @param dict          dictionary containing snapshot restore request
3965
 * @param err_str       In case of an err this string should be populated
3966
 * @param len           length of err_str buffer
3967
 *
3968
 * @return              Negative value on Failure and 0 in success
3969
 */
3970
int
3971
glusterd_handle_snapshot_restore(rpcsvc_request_t *req, glusterd_op_t op,
3972
                                 dict_t *dict, char *err_str,
3973
                                 uint32_t *op_errno, size_t len)
3974
{
3975
    int ret = -1;
3976
    char *snapname = NULL;
3977
    char *buf = NULL;
3978
    glusterd_conf_t *conf = NULL;
3979
    xlator_t *this = THIS;
3980
    glusterd_snap_t *snap = NULL;
3981
    glusterd_volinfo_t *snap_volinfo = NULL;
3982
    int32_t i = 0;
3983
    char key[64] = "";
3984
    int keylen;
3985

3986
    conf = this->private;
3987

3988
    GF_ASSERT(conf);
3989
    GF_ASSERT(req);
3990
    GF_ASSERT(dict);
3991
    GF_ASSERT(err_str);
3992

3993
    ret = dict_get_str(dict, "snapname", &snapname);
3994
    if (ret) {
3995
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3996
               "Failed to "
3997
               "get snapname");
3998
        goto out;
3999
    }
4000

4001
    snap = glusterd_find_snap_by_name(snapname);
4002
    if (!snap) {
4003
        snprintf(err_str, len, "Snapshot (%s) does not exist", snapname);
4004
        *op_errno = EG_NOSNAP;
4005
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND, "%s",
4006
               err_str);
4007
        ret = -1;
4008
        goto out;
4009
    }
4010

4011
    list_for_each_entry(snap_volinfo, &snap->volumes, vol_list)
4012
    {
4013
        i++;
4014
        keylen = snprintf(key, sizeof(key), "volname%d", i);
4015
        buf = gf_strdup(snap_volinfo->parent_volname);
4016
        if (!buf) {
4017
            ret = -1;
4018
            goto out;
4019
        }
4020
        ret = dict_set_dynstrn(dict, key, keylen, buf);
4021
        if (ret) {
4022
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4023
                   "Could not set "
4024
                   "parent volume name %s in the dict",
4025
                   snap_volinfo->parent_volname);
4026
            GF_FREE(buf);
4027
            goto out;
4028
        }
4029
        buf = NULL;
4030
    }
4031

4032
    ret = dict_set_int32_sizen(dict, "volcount", i);
4033
    if (ret) {
4034
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4035
               "Could not save volume count");
4036
        goto out;
4037
    }
4038

4039
    ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
4040
    if (ret) {
4041
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
4042
               "Failed to initiate snap phases");
4043
        goto out;
4044
    }
4045

4046
    ret = 0;
4047

4048
out:
4049
    return ret;
4050
}
4051

4052
glusterd_snap_t *
4053
glusterd_create_snap_object(dict_t *dict, dict_t *rsp_dict)
4054
{
4055
    char *snapname = NULL;
4056
    uuid_t *snap_id = NULL;
4057
    char *description = NULL;
4058
    glusterd_snap_t *snap = NULL;
4059
    xlator_t *this = THIS;
4060
    glusterd_conf_t *priv = NULL;
4061
    int ret = -1;
4062
    int64_t time_stamp = 0;
4063

4064
    priv = this->private;
4065

4066
    GF_ASSERT(dict);
4067
    GF_ASSERT(rsp_dict);
4068

4069
    /* Fetch snapname, description, id and time from dict */
4070
    ret = dict_get_str(dict, "snapname", &snapname);
4071
    if (ret) {
4072
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4073
               "Unable to fetch snapname");
4074
        goto out;
4075
    }
4076

4077
    /* Ignore ret value for description */
4078
    ret = dict_get_str(dict, "description", &description);
4079

4080
    ret = dict_get_bin(dict, "snap-id", (void **)&snap_id);
4081
    if (ret) {
4082
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4083
               "Unable to fetch snap_id");
4084
        goto out;
4085
    }
4086

4087
    ret = dict_get_int64(dict, "snap-time", &time_stamp);
4088
    if (ret) {
4089
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4090
               "Unable to fetch snap-time");
4091
        goto out;
4092
    }
4093
    if (time_stamp <= 0) {
4094
        ret = -1;
4095
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
4096
               "Invalid time-stamp: %" PRId64, time_stamp);
4097
        goto out;
4098
    }
4099

4100
    cds_list_for_each_entry(snap, &priv->snapshots, snap_list)
4101
    {
4102
        if (!strcmp(snap->snapname, snapname) ||
4103
            !gf_uuid_compare(snap->snap_id, *snap_id)) {
4104
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
4105
                   "Found duplicate snap %s (%s)", snap->snapname,
4106
                   uuid_utoa(snap->snap_id));
4107
            ret = -1;
4108
            break;
4109
        }
4110
    }
4111
    if (ret) {
4112
        snap = NULL;
4113
        goto out;
4114
    }
4115

4116
    snap = glusterd_new_snap_object();
4117
    if (!snap) {
4118
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
4119
               "Could not create "
4120
               "the snap object for snap %s",
4121
               snapname);
4122
        goto out;
4123
    }
4124

4125
    gf_strncpy(snap->snapname, snapname, sizeof(snap->snapname));
4126
    gf_uuid_copy(snap->snap_id, *snap_id);
4127
    snap->time_stamp = (time_t)time_stamp;
4128
    /* Set the status as GD_SNAP_STATUS_INIT and once the backend snapshot
4129
       is taken and snap is really ready to use, set the status to
4130
       GD_SNAP_STATUS_IN_USE. This helps in identifying the incomplete
4131
       snapshots and cleaning them up.
4132
    */
4133
    snap->snap_status = GD_SNAP_STATUS_INIT;
4134
    if (description) {
4135
        snap->description = gf_strdup(description);
4136
        if (snap->description == NULL) {
4137
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
4138
                   "Saving the Snapshot Description Failed");
4139
            ret = -1;
4140
            goto out;
4141
        }
4142
    }
4143

4144
    ret = glusterd_store_snap(snap);
4145
    if (ret) {
4146
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
4147
               "Could not store snap"
4148
               "object %s",
4149
               snap->snapname);
4150
        goto out;
4151
    }
4152

4153
    glusterd_list_add_order(&snap->snap_list, &priv->snapshots,
4154
                            glusterd_compare_snap_time);
4155

4156
    gf_msg_trace(this->name, 0, "Snapshot %s added to the list",
4157
                 snap->snapname);
4158

4159
    ret = 0;
4160

4161
out:
4162
    if (ret) {
4163
        if (snap)
4164
            glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_false);
4165
        snap = NULL;
4166
    }
4167

4168
    return snap;
4169
}
4170

4171
/* Added missed_snap_entry to rsp_dict */
4172
int32_t
4173
glusterd_add_missed_snaps_to_dict(dict_t *rsp_dict,
4174
                                  glusterd_volinfo_t *snap_vol,
4175
                                  glusterd_brickinfo_t *brickinfo,
4176
                                  int32_t brick_number, int32_t op)
4177
{
4178
    char *snap_uuid = NULL;
4179
    char missed_snap_entry[PATH_MAX] = "";
4180
    char name_buf[PATH_MAX] = "";
4181
    int32_t missed_snap_count = -1;
4182
    int32_t ret = -1;
4183
    xlator_t *this = THIS;
4184
    int32_t len = 0;
4185

4186
    GF_ASSERT(rsp_dict);
4187
    GF_ASSERT(snap_vol);
4188
    GF_ASSERT(brickinfo);
4189

4190
    snap_uuid = gf_strdup(uuid_utoa(snap_vol->snapshot->snap_id));
4191
    if (!snap_uuid) {
4192
        ret = -1;
4193
        goto out;
4194
    }
4195

4196
    len = snprintf(missed_snap_entry, sizeof(missed_snap_entry),
4197
                   "%s:%s=%s:%d:%s:%d:%d", uuid_utoa(brickinfo->uuid),
4198
                   snap_uuid, snap_vol->volname, brick_number, brickinfo->path,
4199
                   op, GD_MISSED_SNAP_PENDING);
4200
    if ((len < 0) || (len >= sizeof(missed_snap_entry))) {
4201
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
4202
        goto out;
4203
    }
4204

4205
    /* Fetch the missed_snap_count from the dict */
4206
    ret = dict_get_int32(rsp_dict, "missed_snap_count", &missed_snap_count);
4207
    if (ret) {
4208
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4209
                "Key=missed_snap_count", NULL);
4210
        /* Initialize the missed_snap_count for the first time */
4211
        missed_snap_count = 0;
4212
    }
4213

4214
    /* Setting the missed_snap_entry in the rsp_dict */
4215
    snprintf(name_buf, sizeof(name_buf), "missed_snaps_%d", missed_snap_count);
4216
    ret = dict_set_dynstr_with_alloc(rsp_dict, name_buf, missed_snap_entry);
4217
    if (ret) {
4218
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4219
               "Failed to set missed_snap_entry (%s) "
4220
               "in the rsp_dict.",
4221
               missed_snap_entry);
4222
        goto out;
4223
    }
4224
    missed_snap_count++;
4225

4226
    /* Setting the new missed_snap_count in the dict */
4227
    ret = dict_set_int32_sizen(rsp_dict, "missed_snap_count",
4228
                               missed_snap_count);
4229
    if (ret) {
4230
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4231
               "Failed to set missed_snap_count for %s "
4232
               "in the rsp_dict.",
4233
               missed_snap_entry);
4234
        goto out;
4235
    }
4236

4237
out:
4238
    if (snap_uuid)
4239
        GF_FREE(snap_uuid);
4240

4241
    gf_msg_trace(this->name, 0, "Returning %d", ret);
4242
    return ret;
4243
}
4244

4245
int32_t
4246
glusterd_snap_brick_create(glusterd_volinfo_t *snap_volinfo,
4247
                           glusterd_brickinfo_t *brickinfo, int32_t brick_count,
4248
                           int32_t clone, struct glusterd_snap_ops *snap_ops)
4249
{
4250
    int32_t ret = -1;
4251
    xlator_t *this = THIS;
4252
    char clone_volume_id[GD_VOLUME_NAME_MAX] = "";
4253
    char snap_volume_id[GD_VOLUME_NAME_MAX] = "";
4254
    struct stat statbuf = {
4255
        0,
4256
    };
4257

4258
    GF_ASSERT(snap_volinfo);
4259
    GF_ASSERT(brickinfo);
4260

4261
    /* mount the snap logical device on the directory inside
4262
       /run/gluster/snaps/<snapname>/@snap_brick_mount_path
4263
       Way to mount the snap brick via mount api is this.
4264
       ret = mount (device, snap_brick_mount_path, entry->mnt_type,
4265
                    MS_MGC_VAL, "nouuid");
4266
       But for now, mounting using runner apis.
4267
    */
4268
    if (clone) {
4269
        GLUSTERD_GET_UUID_NOHYPHEN(clone_volume_id, snap_volinfo->volume_id);
4270
        ret = snap_ops->activate(brickinfo, snap_volinfo->snapshot->snapname,
4271
                                 clone_volume_id, brick_count);
4272
    } else
4273
        ret = snap_ops->activate(brickinfo, snap_volinfo->snapshot->snapname,
4274
                                 snap_volinfo->volname, brick_count);
4275

4276
    if (ret) {
4277
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_LVM_MOUNT_FAILED,
4278
               "Failed to activate snapshot.");
4279
        goto out;
4280
    }
4281

4282
    ret = sys_stat(brickinfo->path, &statbuf);
4283
    if (ret) {
4284
        gf_msg(this->name, GF_LOG_WARNING, errno, GD_MSG_FILE_OP_FAILED,
4285
               "stat of the brick %s "
4286
               "failed (%s)",
4287
               brickinfo->path, strerror(errno));
4288
        goto out;
4289
    }
4290

4291
    if (clone) {
4292
        ret = sys_lsetxattr(brickinfo->path, GF_XATTR_VOL_ID_KEY,
4293
                            snap_volinfo->volume_id, 16, XATTR_REPLACE);
4294
        if (ret == -1) {
4295
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_SET_XATTR_FAIL,
4296
                   "Failed to set "
4297
                   "extended attribute %s on %s. Reason: "
4298
                   "%s, snap: %s",
4299
                   GF_XATTR_VOL_ID_KEY, brickinfo->path, strerror(errno),
4300
                   snap_volinfo->volname);
4301
            goto out;
4302
        }
4303
    }
4304
out:
4305
    if (ret) {
4306
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_UMOUNTING_SNAP_BRICK,
4307
               "unmounting the snap brick"
4308
               " mount %s",
4309
               brickinfo->path);
4310
        GLUSTERD_GET_UUID_NOHYPHEN(snap_volume_id, snap_volinfo->volume_id);
4311
        snap_ops->deactivate(brickinfo, snap_volinfo->snapshot->snapname,
4312
                             snap_volume_id, brick_count);
4313
    }
4314

4315
    gf_msg_trace(this->name, 0, "Returning %d", ret);
4316
    return ret;
4317
}
4318

4319
static int32_t
4320
glusterd_add_brick_to_snap_volume(dict_t *dict, dict_t *rsp_dict,
4321
                                  glusterd_volinfo_t *snap_vol,
4322
                                  glusterd_brickinfo_t *original_brickinfo,
4323
                                  int64_t volcount, int32_t brick_count,
4324
                                  int clone, struct glusterd_snap_ops *snap_ops)
4325
{
4326
    char key[64] = "";
4327
    int keylen;
4328
    char *value = NULL;
4329
    char *snap_brick_dir = NULL;
4330
    char clone_uuid[64] = "";
4331
    glusterd_brickinfo_t *snap_brickinfo = NULL;
4332
    gf_boolean_t add_missed_snap = _gf_false;
4333
    int32_t ret = -1;
4334
    xlator_t *this = THIS;
4335
    char abspath[PATH_MAX] = "";
4336

4337
    GF_ASSERT(dict);
4338
    GF_ASSERT(rsp_dict);
4339
    GF_ASSERT(snap_vol);
4340
    GF_ASSERT(original_brickinfo);
4341

4342
    snprintf(key, sizeof(key), "vol%" PRId64 ".origin_path%d", volcount,
4343
             brick_count);
4344
    if (clone)
4345
        ret = dict_set_dynstr_with_alloc(dict, key,
4346
                                         original_brickinfo->origin_path);
4347
    else
4348
        ret = dict_set_dynstr_with_alloc(dict, key, original_brickinfo->path);
4349

4350
    if (ret) {
4351
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4352
               "Failed to set %s", key);
4353
        goto out;
4354
    }
4355

4356
    ret = glusterd_brickinfo_new(&snap_brickinfo);
4357
    if (ret) {
4358
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_NEW_INFO_FAIL,
4359
               "initializing the brick for the snap "
4360
               "volume failed (snapname: %s)",
4361
               snap_vol->snapshot->snapname);
4362
        goto out;
4363
    }
4364

4365
    keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%d", volcount,
4366
                      brick_count);
4367
    ret = dict_get_strn(dict, key, keylen, &value);
4368
    if (!ret) {
4369
        /* Update the fstype in original brickinfo as well */
4370
        gf_strncpy(original_brickinfo->fstype, value,
4371
                   sizeof(original_brickinfo->fstype));
4372
        gf_strncpy(snap_brickinfo->fstype, value,
4373
                   sizeof(snap_brickinfo->fstype));
4374
    } else {
4375
        if (is_origin_glusterd(dict) == _gf_true)
4376
            add_missed_snap = _gf_true;
4377
    }
4378

4379
    keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%d", volcount,
4380
                      brick_count);
4381
    ret = dict_get_strn(dict, key, keylen, &value);
4382
    if (!ret) {
4383
        /* Update the snap_type in original brickinfo as well */
4384
        gf_strncpy(original_brickinfo->snap_type, value,
4385
                   sizeof(original_brickinfo->snap_type));
4386
        gf_strncpy(snap_brickinfo->snap_type, value,
4387
                   sizeof(snap_brickinfo->snap_type));
4388
    } else {
4389
        if (is_origin_glusterd(dict) == _gf_true)
4390
            add_missed_snap = _gf_true;
4391
    }
4392

4393
    keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".origin_path%d",
4394
                      volcount, brick_count);
4395
    ret = dict_get_strn(dict, key, keylen, &value);
4396
    if (!ret) {
4397
        /* Update the origin_path to snap_brickinfo */
4398
        gf_strncpy(snap_brickinfo->origin_path, value,
4399
                   sizeof(snap_brickinfo->origin_path));
4400
    } else {
4401
        if (is_origin_glusterd(dict) == _gf_true)
4402
            add_missed_snap = _gf_true;
4403
    }
4404

4405
    keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%d", volcount,
4406
                      brick_count);
4407
    ret = dict_get_strn(dict, key, keylen, &value);
4408
    if (!ret) {
4409
        /* Update the snap_type in original brickinfo as well */
4410
        gf_strncpy(original_brickinfo->snap_type, value,
4411
                   sizeof(original_brickinfo->snap_type));
4412
        gf_strncpy(snap_brickinfo->snap_type, value,
4413
                   sizeof(snap_brickinfo->snap_type));
4414
    } else {
4415
        if (is_origin_glusterd(dict) == _gf_true)
4416
            add_missed_snap = _gf_true;
4417
    }
4418

4419
    keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".mnt_opts%d", volcount,
4420
                      brick_count);
4421
    ret = dict_get_strn(dict, key, keylen, &value);
4422
    if (!ret) {
4423
        /* Update the mnt_opts in original brickinfo as well */
4424
        gf_strncpy(original_brickinfo->mnt_opts, value,
4425
                   sizeof(original_brickinfo->mnt_opts));
4426
        gf_strncpy(snap_brickinfo->mnt_opts, value,
4427
                   sizeof(snap_brickinfo->mnt_opts));
4428
    } else {
4429
        if (is_origin_glusterd(dict) == _gf_true)
4430
            add_missed_snap = _gf_true;
4431
    }
4432

4433
    keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%d", volcount,
4434
                      brick_count);
4435
    ret = dict_get_strn(dict, key, keylen, &snap_brick_dir);
4436
    if (ret) {
4437
        /* Using original brickinfo here because it will be a
4438
         * pending snapshot and storing the original brickinfo
4439
         * will help in mapping while recreating the missed snapshot
4440
         */
4441
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_NOT_FOUND,
4442
               "Unable to fetch "
4443
               "snap mount path(%s). Adding to missed_snap_list",
4444
               key);
4445
        snap_brickinfo->snap_status = -1;
4446

4447
        snap_brick_dir = original_brickinfo->mount_dir;
4448

4449
        /* In origiator node add snaps missed
4450
         * from different nodes to the dict
4451
         */
4452
        if (is_origin_glusterd(dict) == _gf_true)
4453
            add_missed_snap = _gf_true;
4454
    }
4455

4456
    if ((snap_brickinfo->snap_status != -1) &&
4457
        (!gf_uuid_compare(original_brickinfo->uuid, MY_UUID)) &&
4458
        (!glusterd_is_brick_started(original_brickinfo))) {
4459
        /* In case if the brick goes down after prevalidate. */
4460
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICK_DISCONNECTED,
4461
               "brick %s:%s is not"
4462
               " started (snap: %s)",
4463
               original_brickinfo->hostname, original_brickinfo->path,
4464
               snap_vol->snapshot->snapname);
4465

4466
        snap_brickinfo->snap_status = -1;
4467
        add_missed_snap = _gf_true;
4468
    }
4469

4470
    if (add_missed_snap) {
4471
        ret = glusterd_add_missed_snaps_to_dict(
4472
            rsp_dict, snap_vol, original_brickinfo, brick_count + 1,
4473
            GF_SNAP_OPTION_TYPE_CREATE);
4474
        if (ret) {
4475
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSEDSNAP_INFO_SET_FAIL,
4476
                   "Failed to add missed"
4477
                   " snapshot info for %s:%s in the rsp_dict",
4478
                   original_brickinfo->hostname, original_brickinfo->path);
4479
            goto out;
4480
        }
4481
    }
4482

4483
    /* Create brick-path in the format /var/run/gluster/snaps/ *
4484
     * <snap-uuid>/<original-brick#>/snap-brick-dir *
4485
     */
4486
    if (clone) {
4487
        GLUSTERD_GET_UUID_NOHYPHEN(clone_uuid, snap_vol->volume_id);
4488
        ret = snap_ops->brick_path(snap_mount_dir, snap_brickinfo->origin_path,
4489
                                   clone, snap_vol->volname, clone_uuid,
4490
                                   snap_brick_dir, brick_count, snap_brickinfo,
4491
                                   0);
4492
    } else
4493
        ret = snap_ops->brick_path(snap_mount_dir, snap_brickinfo->origin_path,
4494
                                   clone, snap_vol->snapshot->snapname,
4495
                                   snap_vol->volname, snap_brick_dir,
4496
                                   brick_count, snap_brickinfo, 0);
4497

4498
    if (ret)
4499
        goto out;
4500

4501
    ret = gf_canonicalize_path(snap_brickinfo->path);
4502
    if (ret) {
4503
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_CANONICALIZE_FAIL,
4504
               "Failed to canonicalize path");
4505
        goto out;
4506
    }
4507

4508
    gf_strncpy(snap_brickinfo->hostname, original_brickinfo->hostname,
4509
               sizeof(snap_brickinfo->hostname));
4510

4511
    if (!realpath(snap_brickinfo->path, abspath)) {
4512
        /* ENOENT indicates that brick path has not been created which
4513
         * is a valid scenario */
4514
        if (errno != ENOENT) {
4515
            gf_msg(this->name, GF_LOG_CRITICAL, errno,
4516
                   GD_MSG_BRICKINFO_CREATE_FAIL,
4517
                   "realpath () "
4518
                   "failed for brick %s. The underlying filesystem"
4519
                   " may be in bad state",
4520
                   snap_brickinfo->path);
4521
            ret = -1;
4522
            goto out;
4523
        }
4524
    }
4525
    gf_strncpy(snap_brickinfo->real_path, abspath,
4526
               sizeof(snap_brickinfo->real_path));
4527

4528
    gf_strncpy(snap_brickinfo->mount_dir, original_brickinfo->mount_dir,
4529
               sizeof(snap_brickinfo->mount_dir));
4530
    gf_uuid_copy(snap_brickinfo->uuid, original_brickinfo->uuid);
4531
    /* AFR changelog names are based on brick_id and hence the snap
4532
     * volume's bricks must retain the same ID */
4533
    cds_list_add_tail(&snap_brickinfo->brick_list, &snap_vol->bricks);
4534

4535
    if (clone) {
4536
        GLUSTERD_ASSIGN_BRICKID_TO_BRICKINFO(snap_brickinfo, snap_vol,
4537
                                             brick_count);
4538
    } else
4539
        gf_strncpy(snap_brickinfo->brick_id, original_brickinfo->brick_id,
4540
                   sizeof(snap_brickinfo->brick_id));
4541

4542
out:
4543
    if (ret && snap_brickinfo)
4544
        GF_FREE(snap_brickinfo);
4545

4546
    gf_msg_trace(this->name, 0, "Returning %d", ret);
4547
    return ret;
4548
}
4549

4550
static int32_t
4551
glusterd_take_brick_snapshot(dict_t *dict, glusterd_volinfo_t *snap_vol,
4552
                             glusterd_brickinfo_t *brickinfo, int32_t volcount,
4553
                             int32_t brick_count, int32_t clone)
4554
{
4555
    char *origin_path = NULL;
4556
    char *origin_snapname = NULL;
4557
    char snap_volume_id[GD_VOLUME_NAME_MAX] = "";
4558
    char *origin_snap_volume_id = NULL;
4559
    char key[64] = "";
4560
    int keylen;
4561
    int32_t ret = -1;
4562
    gf_boolean_t snap_activate = _gf_false;
4563
    xlator_t *this = THIS;
4564
    glusterd_conf_t *priv = NULL;
4565
    struct glusterd_snap_ops *snap_ops = NULL;
4566
    char *snap_plugin = NULL;
4567

4568
    priv = this->private;
4569
    GF_ASSERT(dict);
4570
    GF_ASSERT(snap_vol);
4571
    GF_ASSERT(brickinfo);
4572
    GF_ASSERT(priv);
4573

4574
    if (!clone) {
4575
        keylen = snprintf(key, sizeof(key), "vol%d.origin_path%d", volcount,
4576
                          brick_count);
4577
        ret = dict_get_strn(dict, key, keylen, &origin_path);
4578
        if (ret) {
4579
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4580
                   "Unable to fetch "
4581
                   "origin_path (%s)",
4582
                   key);
4583
            goto out;
4584
        }
4585
        gf_strncpy(brickinfo->origin_path, origin_path,
4586
                   sizeof(brickinfo->origin_path));
4587
    }
4588

4589
    GLUSTERD_GET_UUID_NOHYPHEN(snap_volume_id, snap_vol->volume_id);
4590

4591
    if (clone) {
4592
        ret = dict_get_ptr(dict, "parent_snap_volume_id",
4593
                           (void **)&origin_snap_volume_id);
4594
        if (ret) {
4595
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4596
                   "Unable to fetch "
4597
                   "parent_snap_volume_id");
4598
            goto out;
4599
        }
4600
        ret = dict_get_ptr(dict, "parent_snapname", (void **)&origin_snapname);
4601
        if (ret) {
4602
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4603
                   "Unable to fetch "
4604
                   "parent_snapname");
4605
            goto out;
4606
        }
4607
        glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
4608

4609
        ret = snap_ops->clone(brickinfo, origin_snapname, origin_snap_volume_id,
4610
                              snap_vol->volname, snap_volume_id, brick_count);
4611
    } else {
4612
        keylen = snprintf(key, sizeof(key), "vol%d.snap_plugin", volcount);
4613
        ret = dict_get_strn(dict, key, keylen, &snap_plugin);
4614
        if (ret) {
4615
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4616
                   "Unable to fetch "
4617
                   "snap_plugin");
4618
            goto out;
4619
        }
4620
        gf_strncpy(snap_vol->snap_plugin, snap_plugin,
4621
                   sizeof(snap_vol->snap_plugin));
4622
        glusterd_snapshot_plugin_by_name(snap_plugin, &snap_ops);
4623
        ret = snap_ops->create(brickinfo, snap_vol->snapshot->snapname,
4624
                               snap_volume_id, brick_count);
4625
    }
4626

4627
    if (ret) {
4628
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
4629
               "Failed to take snapshot of "
4630
               "brick %s:%s",
4631
               brickinfo->hostname, origin_path);
4632
        goto out;
4633
    }
4634

4635
    /* create the complete brick here in case of clone and
4636
     * activate-on-create configuration.
4637
     */
4638
    snap_activate = dict_get_str_boolean(
4639
        priv->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, _gf_false);
4640
    if (clone || snap_activate) {
4641
        ret = glusterd_snap_brick_create(snap_vol, brickinfo, brick_count,
4642
                                         clone, snap_ops);
4643
        if (ret) {
4644
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_CREATION_FAIL,
4645
                   "not able to "
4646
                   "create the brick for the snap %s, volume %s",
4647
                   snap_vol->snapshot->snapname, snap_vol->volname);
4648
            goto out;
4649
        }
4650
    }
4651

4652
out:
4653
    gf_msg_trace(this->name, 0, "Returning %d", ret);
4654
    return ret;
4655
}
4656

4657
static int
4658
glusterd_snap_clear_unsupported_opt(
4659
    glusterd_volinfo_t *volinfo,
4660
    struct gd_snap_unsupported_opt_t *unsupported_opt)
4661
{
4662
    int ret = -1;
4663
    int i = 0;
4664

4665
    GF_VALIDATE_OR_GOTO("glusterd", volinfo, out);
4666

4667
    for (i = 0; unsupported_opt[i].key; i++) {
4668
        glusterd_volinfo_get(volinfo, unsupported_opt[i].key,
4669
                             &unsupported_opt[i].value);
4670

4671
        if (unsupported_opt[i].value) {
4672
            unsupported_opt[i].value = gf_strdup(unsupported_opt[i].value);
4673
            if (!unsupported_opt[i].value) {
4674
                ret = -1;
4675
                goto out;
4676
            }
4677
            dict_del(volinfo->dict, unsupported_opt[i].key);
4678
        }
4679
    }
4680

4681
    ret = 0;
4682
out:
4683
    return ret;
4684
}
4685

4686
static int
4687
glusterd_snap_set_unsupported_opt(
4688
    glusterd_volinfo_t *volinfo,
4689
    struct gd_snap_unsupported_opt_t *unsupported_opt)
4690
{
4691
    int ret = -1;
4692
    int i = 0;
4693

4694
    GF_VALIDATE_OR_GOTO("glusterd", volinfo, out);
4695

4696
    for (i = 0; unsupported_opt[i].key; i++) {
4697
        if (!unsupported_opt[i].value)
4698
            continue;
4699

4700
        ret = dict_set_dynstr(volinfo->dict, unsupported_opt[i].key,
4701
                              unsupported_opt[i].value);
4702
        if (ret) {
4703
            gf_msg("glusterd", GF_LOG_ERROR, -ret, GD_MSG_DICT_SET_FAILED,
4704
                   "dict set failed");
4705
            goto out;
4706
        }
4707
        unsupported_opt[i].value = NULL;
4708
    }
4709

4710
    ret = 0;
4711
out:
4712
    return ret;
4713
}
4714

4715
/* This function will create a new volinfo and then
4716
 * dup the entries from volinfo to the new_volinfo.
4717
 *
4718
 * @param volinfo       volinfo which will be duplicated
4719
 * @param dup_volinfo   new volinfo which will be created
4720
 * @param set_userauth  if this true then auth info is also set
4721
 *
4722
 * @return 0 on success else -1
4723
 */
4724
static int32_t
4725
glusterd_volinfo_dup(glusterd_volinfo_t *volinfo,
4726
                     glusterd_volinfo_t **dup_volinfo,
4727
                     gf_boolean_t set_userauth)
4728
{
4729
    int32_t ret = -1;
4730
    xlator_t *this = THIS;
4731
    glusterd_volinfo_t *new_volinfo = NULL;
4732

4733
    GF_VALIDATE_OR_GOTO(this->name, volinfo, out);
4734
    GF_VALIDATE_OR_GOTO(this->name, dup_volinfo, out);
4735

4736
    ret = glusterd_volinfo_new(&new_volinfo);
4737
    if (ret) {
4738
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_SET_FAIL,
4739
               "not able to create the "
4740
               "duplicate volinfo for the volume %s",
4741
               volinfo->volname);
4742
        goto out;
4743
    }
4744

4745
    new_volinfo->type = volinfo->type;
4746
    new_volinfo->replica_count = volinfo->replica_count;
4747
    new_volinfo->arbiter_count = volinfo->arbiter_count;
4748
    new_volinfo->disperse_count = volinfo->disperse_count;
4749
    new_volinfo->redundancy_count = volinfo->redundancy_count;
4750
    new_volinfo->dist_leaf_count = volinfo->dist_leaf_count;
4751
    new_volinfo->sub_count = volinfo->sub_count;
4752
    new_volinfo->subvol_count = volinfo->subvol_count;
4753
    new_volinfo->transport_type = volinfo->transport_type;
4754
    new_volinfo->brick_count = volinfo->brick_count;
4755
    new_volinfo->quota_conf_version = volinfo->quota_conf_version;
4756
    new_volinfo->quota_xattr_version = volinfo->quota_xattr_version;
4757
    new_volinfo->snap_max_hard_limit = volinfo->snap_max_hard_limit;
4758
    new_volinfo->quota_conf_cksum = volinfo->quota_conf_cksum;
4759
    strcpy(new_volinfo->snap_plugin, volinfo->snap_plugin);
4760

4761
    dict_copy(volinfo->dict, new_volinfo->dict);
4762
    dict_copy(volinfo->gsync_secondaries, new_volinfo->gsync_secondaries);
4763
    dict_copy(volinfo->gsync_active_secondaries,
4764
              new_volinfo->gsync_active_secondaries);
4765
    gd_update_volume_op_versions(new_volinfo);
4766

4767
    if (set_userauth) {
4768
        glusterd_auth_set_username(new_volinfo, volinfo->auth.username);
4769
        glusterd_auth_set_password(new_volinfo, volinfo->auth.password);
4770
    }
4771

4772
    *dup_volinfo = new_volinfo;
4773
    ret = 0;
4774
out:
4775
    if (ret && (NULL != new_volinfo)) {
4776
        (void)glusterd_volinfo_unref(new_volinfo);
4777
    }
4778
    return ret;
4779
}
4780

4781
glusterd_volinfo_t *
4782
glusterd_do_snap_vol(glusterd_volinfo_t *origin_vol, glusterd_snap_t *snap,
4783
                     dict_t *dict, dict_t *rsp_dict, int64_t volcount,
4784
                     int clone)
4785
{
4786
    char key[64] = "";
4787
    int keylen;
4788
    char *username = NULL;
4789
    char *password = NULL;
4790
    glusterd_brickinfo_t *brickinfo = NULL;
4791
    glusterd_conf_t *priv = NULL;
4792
    glusterd_volinfo_t *snap_vol = NULL;
4793
    uuid_t *snap_volid = NULL;
4794
    int32_t ret = -1;
4795
    int32_t brick_count = 0;
4796
    xlator_t *this = THIS;
4797
    char *clonename = NULL;
4798
    gf_boolean_t conf_present = _gf_false;
4799
    int i = 0;
4800
    struct glusterd_snap_ops *snap_ops = NULL;
4801
    char *snap_plugin = NULL;
4802

4803
    struct gd_snap_unsupported_opt_t unsupported_opt[] = {
4804
        {.key = VKEY_FEATURES_QUOTA, .value = NULL},
4805
        {.key = VKEY_FEATURES_INODE_QUOTA, .value = NULL},
4806
        {.key = "feature.deem-statfs", .value = NULL},
4807
        {.key = "features.quota-deem-statfs", .value = NULL},
4808
        {.key = NULL, .value = NULL}};
4809

4810
    priv = this->private;
4811
    GF_ASSERT(priv);
4812
    GF_ASSERT(dict);
4813
    GF_ASSERT(origin_vol);
4814
    GF_ASSERT(rsp_dict);
4815

4816
    /* fetch username, password and vol_id from dict*/
4817
    keylen = snprintf(key, sizeof(key), "volume%" PRId64 "_username", volcount);
4818
    ret = dict_get_strn(dict, key, keylen, &username);
4819
    if (ret) {
4820
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4821
               "Failed to get %s for "
4822
               "snap %s",
4823
               key, snap->snapname);
4824
        goto out;
4825
    }
4826
    keylen = snprintf(key, sizeof(key), "volume%" PRId64 "_password", volcount);
4827
    ret = dict_get_strn(dict, key, keylen, &password);
4828
    if (ret) {
4829
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4830
               "Failed to get %s for "
4831
               "snap %s",
4832
               key, snap->snapname);
4833
        goto out;
4834
    }
4835

4836
    snprintf(key, sizeof(key), "vol%" PRId64 "_volid", volcount);
4837
    ret = dict_get_bin(dict, key, (void **)&snap_volid);
4838
    if (ret) {
4839
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4840
               "Unable to fetch snap_volid");
4841
        goto out;
4842
    }
4843

4844
    /* We are not setting the username and password here as
4845
     * we need to set the user name and password passed in
4846
     * the dictionary
4847
     */
4848
    ret = glusterd_volinfo_dup(origin_vol, &snap_vol, _gf_false);
4849
    if (ret) {
4850
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
4851
               "Failed to duplicate volinfo "
4852
               "for the snapshot %s",
4853
               snap->snapname);
4854
        goto out;
4855
    }
4856

4857
    /* uuid is used as snapshot name.
4858
       This will avoid restrictions on snapshot names provided by user */
4859
    gf_uuid_copy(snap_vol->volume_id, *snap_volid);
4860
    snap_vol->is_snap_volume = _gf_true;
4861
    snap_vol->snapshot = snap;
4862

4863
    if (clone) {
4864
        snap_vol->is_snap_volume = _gf_false;
4865
        ret = dict_get_str(dict, "clonename", &clonename);
4866
        if (ret) {
4867
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4868
                   "Failed to get %s "
4869
                   "for snap %s",
4870
                   key, snap->snapname);
4871
            goto out;
4872
        }
4873
        cds_list_add_tail(&snap_vol->vol_list, &snap->volumes);
4874
        gf_strncpy(snap_vol->volname, clonename, sizeof(snap_vol->volname));
4875
        gf_uuid_copy(snap_vol->restored_from_snap,
4876
                     origin_vol->snapshot->snap_id);
4877
    } else {
4878
        GLUSTERD_GET_UUID_NOHYPHEN(snap_vol->volname, *snap_volid);
4879
        gf_strncpy(snap_vol->parent_volname, origin_vol->volname,
4880
                   sizeof(snap_vol->parent_volname));
4881
        ret = glusterd_list_add_snapvol(origin_vol, snap_vol);
4882
        if (ret) {
4883
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_LIST_SET_FAIL,
4884
                   "could not add the "
4885
                   "snap volume %s to the list",
4886
                   snap_vol->volname);
4887
            goto out;
4888
        }
4889
        /* TODO : Sync before taking a snapshot */
4890
        /* Copy the status and config files of geo-replication before
4891
         * taking a snapshot. During restore operation these files needs
4892
         * to be copied back in /var/lib/glusterd/georeplication/
4893
         */
4894
        ret = glusterd_copy_geo_rep_files(origin_vol, snap_vol, rsp_dict);
4895
        if (ret) {
4896
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
4897
                   "Failed to copy "
4898
                   "geo-rep config and status files for volume %s",
4899
                   origin_vol->volname);
4900
            goto out;
4901
        }
4902
    }
4903

4904
    glusterd_auth_set_username(snap_vol, username);
4905
    glusterd_auth_set_password(snap_vol, password);
4906

4907
    /* Adding snap brickinfos to the snap volinfo */
4908
    brick_count = 0;
4909

4910
    /* During create, Snapshot plugin name is not set to */
4911
    /* snap_vol->snap_plugin. It is available in rest of the calls */
4912
    if (!clone) {
4913
        keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_plugin",
4914
                          volcount);
4915
        ret = dict_get_strn(dict, key, keylen, &snap_plugin);
4916
        if (ret) {
4917
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4918
                   "Unable to fetch "
4919
                   "snap_plugin");
4920
            goto out;
4921
        }
4922
        gf_strncpy(snap_vol->snap_plugin, snap_plugin,
4923
                   sizeof(snap_vol->snap_plugin));
4924
    }
4925
    /* To use generic functions from the plugin */
4926
    glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
4927

4928
    cds_list_for_each_entry(brickinfo, &origin_vol->bricks, brick_list)
4929
    {
4930
        ret = glusterd_add_brick_to_snap_volume(dict, rsp_dict, snap_vol,
4931
                                                brickinfo, volcount,
4932
                                                brick_count, clone, snap_ops);
4933
        if (ret) {
4934
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_ADD_FAIL,
4935
                   "Failed to add the snap brick for "
4936
                   "%s:%s to the snap volume",
4937
                   brickinfo->hostname, brickinfo->path);
4938
            goto out;
4939
        }
4940
        brick_count++;
4941
    }
4942

4943
    /* During snapshot creation if I/O is in progress,
4944
     * then barrier value is enabled. Hence during snapshot create
4945
     * and in-turn snapshot restore the barrier value is set to enable.
4946
     * Because of this further I/O on the mount point fails.
4947
     * Hence remove the barrier key from newly created snap volinfo
4948
     * before storing and generating the brick volfiles. Also update
4949
     * the snap vol's version after removing the barrier key.
4950
     */
4951
    dict_del_sizen(snap_vol->dict, "features.barrier");
4952
    gd_update_volume_op_versions(snap_vol);
4953

4954
    /* *
4955
     * Create the export file from the node where ganesha.enable "on"
4956
     * is executed
4957
     * */
4958
    if (glusterd_is_ganesha_cluster() &&
4959
        glusterd_check_ganesha_export(snap_vol)) {
4960
        if (is_origin_glusterd(dict)) {
4961
            ret = manage_export_config(clonename, "on", NULL);
4962
            if (ret) {
4963
                gf_msg(this->name, GF_LOG_ERROR, 0,
4964
                       GD_MSG_EXPORT_FILE_CREATE_FAIL,
4965
                       "Failed to create"
4966
                       "export file for NFS-Ganesha\n");
4967
                goto out;
4968
            }
4969
        }
4970

4971
        ret = dict_set_dynstr_with_alloc(snap_vol->dict,
4972
                                         "features.cache-invalidation", "on");
4973
        ret = gd_ganesha_send_dbus(clonename, "on");
4974
        if (ret) {
4975
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_EXPORT_FILE_CREATE_FAIL,
4976
                   "Dynamic export addition/deletion failed."
4977
                   " Please see log file for details. Clone name = %s",
4978
                   clonename);
4979
            goto out;
4980
        }
4981
    }
4982
    if (!glusterd_is_ganesha_cluster() &&
4983
        glusterd_check_ganesha_export(snap_vol)) {
4984
        /* This happens when a snapshot was created when Ganesha was
4985
         * enabled globally. Then Ganesha disabled from the cluster.
4986
         * In such cases, we will have the volume level option set
4987
         * on dict, So we have to disable it as it doesn't make sense
4988
         * to keep the option.
4989
         */
4990

4991
        ret = dict_set_dynstr(snap_vol->dict, "ganesha.enable", "off");
4992
        if (ret)
4993
            goto out;
4994
    }
4995

4996
    ret = glusterd_store_volinfo(snap_vol, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
4997
    if (ret) {
4998
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_SET_FAIL,
4999
               "Failed to store snapshot "
5000
               "volinfo (%s) for snap %s",
5001
               snap_vol->volname, snap->snapname);
5002
        goto out;
5003
    }
5004

5005
    ret = glusterd_copy_quota_files(origin_vol, snap_vol, &conf_present);
5006
    if (ret) {
5007
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_VOL_CONFIG_FAIL,
5008
               "Failed to copy quota "
5009
               "config and cksum for volume %s",
5010
               origin_vol->volname);
5011
        goto out;
5012
    }
5013

5014
    if (snap_vol->is_snap_volume) {
5015
        ret = glusterd_snap_clear_unsupported_opt(snap_vol, unsupported_opt);
5016
        if (ret) {
5017
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
5018
                   "Failed to clear quota "
5019
                   "option for the snap %s (volume: %s)",
5020
                   snap->snapname, origin_vol->volname);
5021
            goto out;
5022
        }
5023
    }
5024

5025
    ret = generate_brick_volfiles(snap_vol);
5026
    if (ret) {
5027
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL,
5028
               "generating the brick "
5029
               "volfiles for the snap %s (volume: %s) failed",
5030
               snap->snapname, origin_vol->volname);
5031
        goto reset_option;
5032
    }
5033

5034
    ret = generate_client_volfiles(snap_vol, GF_CLIENT_TRUSTED);
5035
    if (ret) {
5036
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL,
5037
               "generating the trusted "
5038
               "client volfiles for the snap %s (volume: %s) failed",
5039
               snap->snapname, origin_vol->volname);
5040
        goto reset_option;
5041
    }
5042

5043
    ret = generate_client_volfiles(snap_vol, GF_CLIENT_OTHER);
5044
    if (ret) {
5045
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL,
5046
               "generating the client "
5047
               "volfiles for the snap %s (volume: %s) failed",
5048
               snap->snapname, origin_vol->volname);
5049
        goto reset_option;
5050
    }
5051

5052
reset_option:
5053
    if (snap_vol->is_snap_volume) {
5054
        if (glusterd_snap_set_unsupported_opt(snap_vol, unsupported_opt)) {
5055
            ret = -1;
5056
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
5057
                   "Failed to reset quota "
5058
                   "option for the snap %s (volume: %s)",
5059
                   snap->snapname, origin_vol->volname);
5060
        }
5061
    }
5062
out:
5063
    if (ret) {
5064
        for (i = 0; unsupported_opt[i].key; i++)
5065
            GF_FREE(unsupported_opt[i].value);
5066

5067
        if (snap_vol) {
5068
            if (glusterd_is_ganesha_cluster() &&
5069
                glusterd_check_ganesha_export(snap_vol)) {
5070
                if (is_origin_glusterd(dict)) {
5071
                    ret = manage_export_config(clonename, "on", NULL);
5072
                    if (ret) {
5073
                        gf_msg(this->name, GF_LOG_ERROR, 0,
5074
                               GD_MSG_EXPORT_FILE_CREATE_FAIL,
5075
                               "Failed to create"
5076
                               "export file for NFS-Ganesha\n");
5077
                    }
5078
                }
5079

5080
                ret = gd_ganesha_send_dbus(clonename, "off");
5081
                if (ret) {
5082
                    gf_msg(this->name, GF_LOG_ERROR, 0,
5083
                           GD_MSG_EXPORT_FILE_CREATE_FAIL,
5084
                           "Dynamic export addition/deletion failed."
5085
                           " Please see log file for details. Clone name = %s",
5086
                           clonename);
5087
                }
5088
            }
5089

5090
            glusterd_snap_volume_remove(rsp_dict, snap_vol, _gf_true, _gf_true);
5091
        }
5092
        snap_vol = NULL;
5093
    }
5094

5095
    return snap_vol;
5096
}
5097

5098
/*This is the prevalidate function for both activate and deactive of snap
5099
 * For Activate operation pass is_op_activate as _gf_true
5100
 * For Deactivate operation pass is_op_activate as _gf_false
5101
 * */
5102
int
5103
glusterd_snapshot_activate_deactivate_prevalidate(dict_t *dict,
5104
                                                  char **op_errstr,
5105
                                                  uint32_t *op_errno,
5106
                                                  dict_t *rsp_dict,
5107
                                                  gf_boolean_t is_op_activate)
5108
{
5109
    int32_t ret = -1;
5110
    char *snapname = NULL;
5111
    xlator_t *this = THIS;
5112
    glusterd_snap_t *snap = NULL;
5113
    glusterd_volinfo_t *snap_volinfo = NULL;
5114
    char err_str[PATH_MAX] = "";
5115
    gf_loglevel_t loglevel = GF_LOG_ERROR;
5116
    glusterd_volume_status volume_status = GLUSTERD_STATUS_STOPPED;
5117
    int flags = 0;
5118

5119
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5120

5121
    if (!dict || !op_errstr) {
5122
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5123
               "input parameters NULL");
5124
        goto out;
5125
    }
5126

5127
    ret = dict_get_str(dict, "snapname", &snapname);
5128
    if (ret) {
5129
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5130
               "Getting the snap name "
5131
               "failed");
5132
        goto out;
5133
    }
5134

5135
    snap = glusterd_find_snap_by_name(snapname);
5136
    if (!snap) {
5137
        snprintf(err_str, sizeof(err_str),
5138
                 "Snapshot (%s) does not "
5139
                 "exist.",
5140
                 snapname);
5141
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
5142
                "Snapname=%s", snapname, NULL);
5143
        *op_errno = EG_NOSNAP;
5144
        ret = -1;
5145
        goto out;
5146
    }
5147

5148
    /* If its activation of snap then fetch the flags */
5149
    if (is_op_activate) {
5150
        ret = dict_get_int32(dict, "flags", &flags);
5151
        if (ret) {
5152
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5153
                   "Unable to get flags");
5154
            goto out;
5155
        }
5156
    }
5157

5158
    /* TODO : As of now there is only volume in snapshot.
5159
     * Change this when multiple volume snapshot is introduced
5160
     */
5161
    snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5162
                                  vol_list);
5163
    if (!snap_volinfo) {
5164
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOLINFO_GET_FAIL,
5165
               "Unable to fetch snap_volinfo");
5166
        ret = -1;
5167
        goto out;
5168
    }
5169

5170
    /*TODO: When multiple snapvolume are involved a cumulative
5171
     * logic is required to tell whether is snapshot is
5172
     * started/partially started/stopped*/
5173
    if (is_op_activate) {
5174
        volume_status = GLUSTERD_STATUS_STARTED;
5175
    }
5176

5177
    if (snap_volinfo->status == volume_status) {
5178
        if (is_op_activate) {
5179
            /* if flag is to GF_CLI_FLAG_OP_FORCE
5180
             * try to start the snap volume, even
5181
             * if the volume_status is GLUSTERD_STATUS_STARTED.
5182
             * By doing so we try to bring
5183
             * back the brick processes that are down*/
5184
            if (!(flags & GF_CLI_FLAG_OP_FORCE)) {
5185
                snprintf(err_str, sizeof(err_str),
5186
                         "Snapshot %s is already activated.", snapname);
5187
                *op_errno = EINVAL;
5188
                ret = -1;
5189
            }
5190
        } else {
5191
            snprintf(err_str, sizeof(err_str),
5192
                     "Snapshot %s is already deactivated.", snapname);
5193
            *op_errno = EINVAL;
5194
            ret = -1;
5195
        }
5196
        goto out;
5197
    }
5198
    ret = 0;
5199
out:
5200

5201
    if (ret && err_str[0] != '\0' && op_errstr) {
5202
        gf_msg(this->name, loglevel, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
5203
               err_str);
5204
        *op_errstr = gf_strdup(err_str);
5205
    }
5206

5207
    return ret;
5208
}
5209

5210
int32_t
5211
glusterd_handle_snapshot_delete_vol(dict_t *dict, char *err_str,
5212
                                    uint32_t *op_errno, int len)
5213
{
5214
    int32_t ret = -1;
5215
    glusterd_volinfo_t *volinfo = NULL;
5216
    xlator_t *this = THIS;
5217
    char *volname = NULL;
5218

5219
    GF_ASSERT(dict);
5220
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5221

5222
    ret = dict_get_str(dict, "volname", &volname);
5223
    if (ret) {
5224
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5225
               "Failed to get "
5226
               "volume name");
5227
        goto out;
5228
    }
5229

5230
    ret = glusterd_volinfo_find(volname, &volinfo);
5231
    if (ret) {
5232
        snprintf(err_str, len, "Volume (%s) does not exist", volname);
5233
        *op_errno = EG_NOVOL;
5234
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
5235
               "Failed to get volinfo of "
5236
               "volume %s",
5237
               volname);
5238
        goto out;
5239
    }
5240

5241
    ret = glusterd_snapshot_get_vol_snapnames(dict, volinfo);
5242
    if (ret) {
5243
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_LIST_GET_FAIL,
5244
               "Failed to get snapshot list for volume %s", volname);
5245
        goto out;
5246
    }
5247

5248
    ret = 0;
5249
out:
5250
    return ret;
5251
}
5252

5253
static int32_t
5254
glusterd_handle_snapshot_delete_all(dict_t *dict)
5255
{
5256
    int32_t ret = -1;
5257
    int32_t i = 0;
5258
    char key[32] = "";
5259
    glusterd_conf_t *priv = NULL;
5260
    glusterd_snap_t *snap = NULL;
5261
    glusterd_snap_t *tmp_snap = NULL;
5262
    xlator_t *this = THIS;
5263

5264
    this = THIS;
5265
    priv = this->private;
5266
    GF_ASSERT(priv);
5267

5268
    GF_ASSERT(dict);
5269

5270
    cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
5271
    {
5272
        /* indexing from 1 to n, to keep it uniform with other code
5273
         * paths
5274
         */
5275
        i++;
5276
        ret = snprintf(key, sizeof(key), "snapname%d", i);
5277
        if (ret < 0) {
5278
            goto out;
5279
        }
5280

5281
        ret = dict_set_dynstr_with_alloc(dict, key, snap->snapname);
5282
        if (ret) {
5283
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5284
                   "Could not save "
5285
                   "snap name");
5286
            goto out;
5287
        }
5288
    }
5289

5290
    ret = dict_set_int32_sizen(dict, "snapcount", i);
5291
    if (ret) {
5292
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5293
               "Could not save snapcount");
5294
        goto out;
5295
    }
5296

5297
    ret = 0;
5298

5299
out:
5300
    return ret;
5301
}
5302

5303
int32_t
5304
glusterd_handle_snapshot_delete_type_snap(rpcsvc_request_t *req,
5305
                                          glusterd_op_t op, dict_t *dict,
5306
                                          char *err_str, uint32_t *op_errno,
5307
                                          size_t len)
5308
{
5309
    int32_t ret = -1;
5310
    int64_t volcount = 0;
5311
    char *snapname = NULL;
5312
    char *volname = NULL;
5313
    char key[64] = "";
5314
    int keylen;
5315
    glusterd_snap_t *snap = NULL;
5316
    glusterd_volinfo_t *snap_vol = NULL;
5317
    glusterd_volinfo_t *tmp = NULL;
5318
    xlator_t *this = THIS;
5319

5320
    GF_ASSERT(req);
5321
    GF_ASSERT(dict);
5322
    GF_ASSERT(err_str);
5323

5324
    ret = dict_get_str(dict, "snapname", &snapname);
5325
    if (ret) {
5326
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5327
               "Failed to get snapname");
5328
        goto out;
5329
    }
5330

5331
    snap = glusterd_find_snap_by_name(snapname);
5332
    if (!snap) {
5333
        snprintf(err_str, len, "Snapshot (%s) does not exist", snapname);
5334
        *op_errno = EG_NOSNAP;
5335
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND, "%s",
5336
               err_str);
5337
        ret = -1;
5338
        goto out;
5339
    }
5340

5341
    /* Set volnames in the dict to get mgmt_v3 lock */
5342
    cds_list_for_each_entry_safe(snap_vol, tmp, &snap->volumes, vol_list)
5343
    {
5344
        volcount++;
5345
        volname = gf_strdup(snap_vol->parent_volname);
5346
        if (!volname) {
5347
            ret = -1;
5348
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
5349
                   "strdup failed");
5350
            goto out;
5351
        }
5352

5353
        keylen = snprintf(key, sizeof(key), "volname%" PRId64, volcount);
5354
        ret = dict_set_dynstrn(dict, key, keylen, volname);
5355
        if (ret) {
5356
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5357
                   "Failed to set "
5358
                   "volume name in dictionary");
5359
            GF_FREE(volname);
5360
            goto out;
5361
        }
5362
        volname = NULL;
5363
    }
5364
    ret = dict_set_int64(dict, "volcount", volcount);
5365
    if (ret) {
5366
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5367
               "Failed to set volcount");
5368
        goto out;
5369
    }
5370

5371
    ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
5372
    if (ret) {
5373
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
5374
               "Failed to initiate snap "
5375
               "phases");
5376
        goto out;
5377
    }
5378

5379
    ret = 0;
5380

5381
out:
5382
    return ret;
5383
}
5384

5385
/* This is a snapshot remove handler function. This function will be
5386
 * executed in the originator node. This function is responsible for
5387
 * calling mgmt v3 framework to do the actual remove on all the bricks
5388
 *
5389
 * @param req           RPC request object
5390
 * @param op            gluster operation
5391
 * @param dict          dictionary containing snapshot remove request
5392
 * @param err_str       In case of an err this string should be populated
5393
 * @param len           length of err_str buffer
5394
 *
5395
 * @return              Negative value on Failure and 0 in success
5396
 */
5397
int
5398
glusterd_handle_snapshot_delete(rpcsvc_request_t *req, glusterd_op_t op,
5399
                                dict_t *dict, char *err_str, uint32_t *op_errno,
5400
                                size_t len)
5401
{
5402
    int ret = -1;
5403
    xlator_t *this = THIS;
5404
    int32_t delete_cmd = -1;
5405

5406
    GF_ASSERT(req);
5407
    GF_ASSERT(dict);
5408
    GF_ASSERT(err_str);
5409
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5410

5411
    ret = dict_get_int32(dict, "sub-cmd", &delete_cmd);
5412
    if (ret) {
5413
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
5414
               "Failed to get sub-cmd");
5415
        goto out;
5416
    }
5417

5418
    switch (delete_cmd) {
5419
        case GF_SNAP_DELETE_TYPE_SNAP:
5420
        case GF_SNAP_DELETE_TYPE_ITER:
5421
            ret = glusterd_handle_snapshot_delete_type_snap(
5422
                req, op, dict, err_str, op_errno, len);
5423
            if (ret) {
5424
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5425
                       "Failed to handle "
5426
                       "snapshot delete for type SNAP");
5427
                goto out;
5428
            }
5429
            break;
5430

5431
        case GF_SNAP_DELETE_TYPE_ALL:
5432
            ret = glusterd_handle_snapshot_delete_all(dict);
5433
            if (ret) {
5434
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5435
                       "Failed to handle "
5436
                       "snapshot delete for type ALL");
5437
                goto out;
5438
            }
5439
            break;
5440

5441
        case GF_SNAP_DELETE_TYPE_VOL:
5442
            ret = glusterd_handle_snapshot_delete_vol(dict, err_str, op_errno,
5443
                                                      len);
5444
            if (ret) {
5445
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5446
                       "Failed to handle "
5447
                       "snapshot delete for type VOL");
5448
                goto out;
5449
            }
5450
            break;
5451

5452
        default:
5453
            *op_errno = EINVAL;
5454
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
5455
                   "Wrong snapshot delete type");
5456
            break;
5457
    }
5458

5459
    if (ret == 0 && (delete_cmd == GF_SNAP_DELETE_TYPE_ALL ||
5460
                     delete_cmd == GF_SNAP_DELETE_TYPE_VOL)) {
5461
        ret = glusterd_op_send_cli_response(op, 0, 0, req, dict, err_str);
5462
        if (ret) {
5463
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
5464
                   "Failed to send cli "
5465
                   "response");
5466
            goto out;
5467
        }
5468
    }
5469
    ret = 0;
5470
out:
5471
    return ret;
5472
}
5473

5474
int
5475
glusterd_snapshot_remove_prevalidate(dict_t *dict, char **op_errstr,
5476
                                     uint32_t *op_errno, dict_t *rsp_dict)
5477
{
5478
    int32_t ret = -1;
5479
    char *snapname = NULL;
5480
    xlator_t *this = THIS;
5481
    glusterd_snap_t *snap = NULL;
5482

5483
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5484

5485
    if (!dict || !op_errstr) {
5486
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5487
               "input parameters NULL");
5488
        goto out;
5489
    }
5490

5491
    ret = dict_get_str(dict, "snapname", &snapname);
5492
    if (ret) {
5493
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5494
               "Getting the snap name "
5495
               "failed");
5496
        goto out;
5497
    }
5498

5499
    snap = glusterd_find_snap_by_name(snapname);
5500
    if (!snap) {
5501
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5502
               "Snapshot (%s) does not exist", snapname);
5503
        *op_errno = EG_NOSNAP;
5504
        ret = -1;
5505
        goto out;
5506
    }
5507

5508
    ret = dict_set_dynstr_with_alloc(dict, "snapuuid",
5509
                                     uuid_utoa(snap->snap_id));
5510
    if (ret) {
5511
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5512
               "Failed to set snap "
5513
               "uuid in response dictionary for %s snapshot",
5514
               snap->snapname);
5515
        goto out;
5516
    }
5517

5518
    ret = 0;
5519
out:
5520
    return ret;
5521
}
5522

5523
int
5524
glusterd_snapshot_status_prevalidate(dict_t *dict, char **op_errstr,
5525
                                     uint32_t *op_errno, dict_t *rsp_dict)
5526
{
5527
    int ret = -1;
5528
    char *snapname = NULL;
5529
    glusterd_conf_t *conf = NULL;
5530
    xlator_t *this = THIS;
5531
    int32_t cmd = -1;
5532
    glusterd_volinfo_t *volinfo = NULL;
5533
    char *volname = NULL;
5534

5535
    conf = this->private;
5536
    GF_ASSERT(conf);
5537
    GF_ASSERT(op_errstr);
5538
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5539

5540
    if (!dict) {
5541
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5542
               "Input dict is NULL");
5543
        goto out;
5544
    }
5545

5546
    ret = dict_get_int32(dict, "sub-cmd", &cmd);
5547
    if (ret) {
5548
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5549
               "Could not fetch status cmd");
5550
        goto out;
5551
    }
5552

5553
    switch (cmd) {
5554
        case GF_SNAP_STATUS_TYPE_ALL: {
5555
            break;
5556
        }
5557
        case GF_SNAP_STATUS_TYPE_ITER:
5558
        case GF_SNAP_STATUS_TYPE_SNAP: {
5559
            ret = dict_get_str(dict, "snapname", &snapname);
5560
            if (ret) {
5561
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5562
                       "Could not fetch snapname");
5563
                goto out;
5564
            }
5565

5566
            if (!glusterd_find_snap_by_name(snapname)) {
5567
                ret = gf_asprintf(op_errstr,
5568
                                  "Snapshot (%s) "
5569
                                  "does not exist",
5570
                                  snapname);
5571
                *op_errno = EG_NOSNAP;
5572
                if (ret < 0) {
5573
                    goto out;
5574
                }
5575
                ret = -1;
5576
                gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5577
                       "Snapshot (%s) does not exist", snapname);
5578
                goto out;
5579
            }
5580
            break;
5581
        }
5582
        case GF_SNAP_STATUS_TYPE_VOL: {
5583
            ret = dict_get_str(dict, "volname", &volname);
5584
            if (ret) {
5585
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5586
                       "Could not fetch volname");
5587
                goto out;
5588
            }
5589

5590
            ret = glusterd_volinfo_find(volname, &volinfo);
5591
            if (ret) {
5592
                ret = gf_asprintf(op_errstr,
5593
                                  "Volume (%s) "
5594
                                  "does not exist",
5595
                                  volname);
5596
                *op_errno = EG_NOVOL;
5597
                if (ret < 0) {
5598
                    goto out;
5599
                }
5600
                ret = -1;
5601
                gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
5602
                       "Volume "
5603
                       "%s not present",
5604
                       volname);
5605
                goto out;
5606
            }
5607
            break;
5608
        }
5609
        default: {
5610
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
5611
                   "Invalid command");
5612
            *op_errno = EINVAL;
5613
            break;
5614
        }
5615
    }
5616
    ret = 0;
5617

5618
out:
5619
    return ret;
5620
}
5621

5622
int32_t
5623
glusterd_snapshot_activate_commit(dict_t *dict, char **op_errstr,
5624
                                  dict_t *rsp_dict)
5625
{
5626
    int32_t ret = -1;
5627
    char *snapname = NULL;
5628
    glusterd_snap_t *snap = NULL;
5629
    glusterd_volinfo_t *snap_volinfo = NULL;
5630
    glusterd_brickinfo_t *brickinfo = NULL;
5631
    xlator_t *this = THIS;
5632
    int flags = 0;
5633
    int brick_count = -1;
5634
    struct glusterd_snap_ops *snap_ops = NULL;
5635

5636
    GF_ASSERT(dict);
5637
    GF_ASSERT(rsp_dict);
5638
    GF_ASSERT(op_errstr);
5639

5640
    if (!dict || !op_errstr) {
5641
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5642
               "input parameters NULL");
5643
        goto out;
5644
    }
5645

5646
    ret = dict_get_str(dict, "snapname", &snapname);
5647
    if (ret) {
5648
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5649
               "Getting the snap name "
5650
               "failed");
5651
        goto out;
5652
    }
5653

5654
    ret = dict_get_int32(dict, "flags", &flags);
5655
    if (ret) {
5656
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5657
               "Unable to get flags");
5658
        goto out;
5659
    }
5660

5661
    snap = glusterd_find_snap_by_name(snapname);
5662
    if (!snap) {
5663
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5664
               "Snapshot (%s) does not exist", snapname);
5665
        ret = -1;
5666
        goto out;
5667
    }
5668

5669
    /* TODO : As of now there is only volume in snapshot.
5670
     * Change this when multiple volume snapshot is introduced
5671
     */
5672
    snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5673
                                  vol_list);
5674
    if (!snap_volinfo) {
5675
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
5676
               "Unable to fetch snap_volinfo");
5677
        ret = -1;
5678
        goto out;
5679
    }
5680

5681
    glusterd_snapshot_plugin_by_name(snap_volinfo->snap_plugin, &snap_ops);
5682

5683
    /* create the complete brick here */
5684
    cds_list_for_each_entry(brickinfo, &snap_volinfo->bricks, brick_list)
5685
    {
5686
        brick_count++;
5687
        if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
5688
            continue;
5689

5690
        ret = glusterd_snap_brick_create(snap_volinfo, brickinfo, brick_count,
5691
                                         _gf_false, snap_ops);
5692
        if (ret) {
5693
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_CREATION_FAIL,
5694
                   "not able to "
5695
                   "create the brick for the snap %s, volume %s",
5696
                   snap_volinfo->snapshot->snapname, snap_volinfo->volname);
5697
            goto out;
5698
        }
5699
    }
5700

5701
    ret = glusterd_start_volume(snap_volinfo, flags, _gf_true);
5702

5703
    if (ret) {
5704
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
5705
               "Failed to activate snap volume %s of the snap %s",
5706
               snap_volinfo->volname, snap->snapname);
5707
        goto out;
5708
    }
5709

5710
    ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
5711
                                     uuid_utoa(snap->snap_id));
5712
    if (ret) {
5713
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5714
               "Failed to set snap "
5715
               "uuid in response dictionary for %s snapshot",
5716
               snap->snapname);
5717
        goto out;
5718
    }
5719

5720
    ret = 0;
5721
out:
5722
    return ret;
5723
}
5724

5725
int32_t
5726
glusterd_snapshot_deactivate_commit(dict_t *dict, char **op_errstr,
5727
                                    dict_t *rsp_dict)
5728
{
5729
    int32_t ret = -1;
5730
    char *snapname = NULL;
5731
    glusterd_snap_t *snap = NULL;
5732
    glusterd_volinfo_t *snap_volinfo = NULL;
5733
    xlator_t *this = THIS;
5734
    char snap_path[PATH_MAX] = "";
5735

5736
    GF_ASSERT(dict);
5737
    GF_ASSERT(rsp_dict);
5738
    GF_ASSERT(op_errstr);
5739

5740
    if (!dict || !op_errstr) {
5741
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5742
               "input parameters NULL");
5743
        goto out;
5744
    }
5745

5746
    ret = dict_get_str(dict, "snapname", &snapname);
5747
    if (ret) {
5748
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5749
               "Getting the snap name "
5750
               "failed");
5751
        goto out;
5752
    }
5753

5754
    snap = glusterd_find_snap_by_name(snapname);
5755
    if (!snap) {
5756
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5757
               "Snapshot (%s) does not exist", snapname);
5758
        ret = -1;
5759
        goto out;
5760
    }
5761

5762
    /* TODO : As of now there is only volume in snapshot.
5763
     * Change this when multiple volume snapshot is introduced
5764
     */
5765
    snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5766
                                  vol_list);
5767
    if (!snap_volinfo) {
5768
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
5769
               "Unable to fetch snap_volinfo");
5770
        ret = -1;
5771
        goto out;
5772
    }
5773

5774
    ret = glusterd_stop_volume(snap_volinfo);
5775
    if (ret) {
5776
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_DEACTIVATE_FAIL,
5777
               "Failed to deactivate"
5778
               "snap %s",
5779
               snapname);
5780
        goto out;
5781
    }
5782

5783
    ret = glusterd_snap_unmount(this, snap_volinfo);
5784
    if (ret) {
5785
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_UMOUNT_FAIL,
5786
               "Failed to unmounts for %s", snap->snapname);
5787
    }
5788

5789
    /*Remove /var/run/gluster/snaps/<snap-name> entry for deactivated snaps.
5790
     * This entry will be created again during snap activate.
5791
     */
5792
    snprintf(snap_path, sizeof(snap_path), "%s/%s", snap_mount_dir, snapname);
5793
    ret = recursive_rmdir(snap_path);
5794
    if (ret) {
5795
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
5796
               "Failed to remove "
5797
               "%s directory : error : %s",
5798
               snap_path, strerror(errno));
5799
        goto out;
5800
    }
5801

5802
    ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
5803
                                     uuid_utoa(snap->snap_id));
5804
    if (ret) {
5805
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5806
               "Failed to set snap "
5807
               "uuid in response dictionary for %s snapshot",
5808
               snap->snapname);
5809
        goto out;
5810
    }
5811

5812
    ret = 0;
5813
out:
5814
    return ret;
5815
}
5816

5817
int32_t
5818
glusterd_snapshot_remove_commit(dict_t *dict, char **op_errstr,
5819
                                dict_t *rsp_dict)
5820
{
5821
    int32_t ret = -1;
5822
    char *snapname = NULL;
5823
    char *dup_snapname = NULL;
5824
    glusterd_snap_t *snap = NULL;
5825
    glusterd_conf_t *priv = NULL;
5826
    glusterd_volinfo_t *snap_volinfo = NULL;
5827
    xlator_t *this = THIS;
5828

5829
    GF_ASSERT(dict);
5830
    GF_ASSERT(rsp_dict);
5831
    GF_ASSERT(op_errstr);
5832

5833
    priv = this->private;
5834
    GF_ASSERT(priv);
5835

5836
    if (!dict || !op_errstr) {
5837
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5838
               "input parameters NULL");
5839
        goto out;
5840
    }
5841

5842
    ret = dict_get_str(dict, "snapname", &snapname);
5843
    if (ret) {
5844
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5845
               "Getting the snap name "
5846
               "failed");
5847
        goto out;
5848
    }
5849

5850
    snap = glusterd_find_snap_by_name(snapname);
5851
    if (!snap) {
5852
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5853
               "Snapshot (%s) does not exist", snapname);
5854
        ret = -1;
5855
        goto out;
5856
    }
5857

5858
    ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
5859
                                     uuid_utoa(snap->snap_id));
5860
    if (ret) {
5861
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5862
               "Failed to set snap uuid in "
5863
               "response dictionary for %s snapshot",
5864
               snap->snapname);
5865
        goto out;
5866
    }
5867

5868
    /* Save the snap status as GD_SNAP_STATUS_DECOMMISSION so
5869
     * that if the node goes down the snap would be removed
5870
     */
5871
    snap->snap_status = GD_SNAP_STATUS_DECOMMISSION;
5872
    ret = glusterd_store_snap(snap);
5873
    if (ret) {
5874
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJECT_STORE_FAIL,
5875
               "Failed to "
5876
               "store snap object %s",
5877
               snap->snapname);
5878
        goto out;
5879
    } else
5880
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_OP_SUCCESS,
5881
               "Successfully marked "
5882
               "snap %s for decommission.",
5883
               snap->snapname);
5884

5885
    if (is_origin_glusterd(dict) == _gf_true) {
5886
        /* TODO : As of now there is only volume in snapshot.
5887
         * Change this when multiple volume snapshot is introduced
5888
         */
5889
        snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5890
                                      vol_list);
5891
        if (!snap_volinfo) {
5892
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
5893
                   "Unable to fetch snap_volinfo");
5894
            ret = -1;
5895
            goto out;
5896
        }
5897

5898
        /* From origin glusterd check if      *
5899
         * any peers with snap bricks is down */
5900
        ret = glusterd_find_missed_snap(rsp_dict, snap_volinfo, &priv->peers,
5901
                                        GF_SNAP_OPTION_TYPE_DELETE);
5902
        if (ret) {
5903
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_GET_FAIL,
5904
                   "Failed to find missed snap deletes");
5905
            goto out;
5906
        }
5907
    }
5908

5909
    ret = glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_false, _gf_false);
5910
    if (ret) {
5911
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5912
               "Failed to remove snap %s", snapname);
5913
        goto out;
5914
    }
5915

5916
    dup_snapname = gf_strdup(snapname);
5917
    if (!dup_snapname) {
5918
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
5919
               "Strdup failed");
5920
        ret = -1;
5921
        goto out;
5922
    }
5923

5924
    ret = dict_set_dynstr(rsp_dict, "snapname", dup_snapname);
5925
    if (ret) {
5926
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5927
               "Failed to set the snapname");
5928
        GF_FREE(dup_snapname);
5929
        goto out;
5930
    }
5931

5932
    ret = 0;
5933
out:
5934
    return ret;
5935
}
5936

5937
int32_t
5938
glusterd_do_snap_cleanup(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
5939
{
5940
    int32_t ret = -1;
5941
    char *name = NULL;
5942
    char *volname = NULL;
5943
    xlator_t *this = THIS;
5944
    glusterd_conf_t *conf = NULL;
5945
    glusterd_snap_t *snap = NULL;
5946

5947
    conf = this->private;
5948
    GF_ASSERT(conf);
5949

5950
    if (!dict || !op_errstr) {
5951
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5952
               "input parameters NULL");
5953
        goto out;
5954
    }
5955

5956
    /* As of now snapshot of multiple volumes are not supported */
5957
    ret = dict_get_str(dict, "volname1", &volname);
5958
    if (ret) {
5959
        gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5960
               "Unable to get"
5961
               " volume name");
5962
        goto out;
5963
    }
5964

5965
    ret = dict_get_str(dict, "snapname", &name);
5966
    if (ret) {
5967
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5968
               "getting the snap "
5969
               "name failed (volume: %s)",
5970
               volname);
5971
        goto out;
5972
    }
5973

5974
    /*
5975
      If the snapname is not found that means the failure happened at
5976
      staging, or in commit, before the snap object is created, in which
5977
      case there is nothing to cleanup. So set ret to 0.
5978
    */
5979
    snap = glusterd_find_snap_by_name(name);
5980
    if (!snap) {
5981
        gf_msg(this->name, GF_LOG_INFO, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5982
               "Snapshot (%s) does not exist", name);
5983
        ret = 0;
5984
        goto out;
5985
    }
5986

5987
    ret = glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_false);
5988
    if (ret) {
5989
        /* Ignore failure as this is a cleanup of half cooked
5990
           snapshot */
5991
        gf_msg_debug(this->name, 0, "removing the snap %s failed", name);
5992
        ret = 0;
5993
    }
5994

5995
    name = NULL;
5996

5997
    ret = 0;
5998

5999
out:
6000

6001
    return ret;
6002
}
6003

6004
/* In case of a successful, delete or create operation, during post_validate
6005
 * * look for missed snap operations and update the missed snap lists */
6006
int32_t
6007
glusterd_snapshot_update_snaps_post_validate(dict_t *dict, char **op_errstr,
6008
                                             dict_t *rsp_dict)
6009
{
6010
    int32_t ret = -1;
6011
    int32_t missed_snap_count = -1;
6012
    xlator_t *this = THIS;
6013

6014
    GF_ASSERT(dict);
6015
    GF_ASSERT(rsp_dict);
6016
    GF_ASSERT(op_errstr);
6017

6018
    ret = dict_get_int32(dict, "missed_snap_count", &missed_snap_count);
6019
    if (ret) {
6020
        gf_msg_debug(this->name, 0, "No missed snaps");
6021
        ret = 0;
6022
        goto out;
6023
    }
6024

6025
    ret = glusterd_add_missed_snaps_to_list(dict, missed_snap_count);
6026
    if (ret) {
6027
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSEDSNAP_INFO_SET_FAIL,
6028
               "Failed to add missed snaps to list");
6029
        goto out;
6030
    }
6031

6032
    ret = glusterd_store_update_missed_snaps();
6033
    if (ret) {
6034
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSEDSNAP_INFO_SET_FAIL,
6035
               "Failed to update missed_snaps_list");
6036
        goto out;
6037
    }
6038

6039
out:
6040
    gf_msg_trace(this->name, 0, "Returning %d", ret);
6041
    return ret;
6042
}
6043

6044
int
6045
glusterd_take_brick_snapshot_task(void *opaque)
6046
{
6047
    int ret = 0;
6048
    int32_t clone = 0;
6049
    snap_create_args_t *snap_args = NULL;
6050
    char *clonename = NULL;
6051
    char key[64] = "";
6052
    int keylen;
6053

6054
    GF_ASSERT(opaque);
6055

6056
    snap_args = (snap_create_args_t *)opaque;
6057
    THIS = snap_args->this;
6058

6059
    /* Try and fetch clonename. If present set status with clonename *
6060
     * else do so as snap-vol */
6061
    ret = dict_get_str(snap_args->dict, "clonename", &clonename);
6062
    if (ret) {
6063
        keylen = snprintf(key, sizeof(key), "snap-vol%d.brick%d.status",
6064
                          snap_args->volcount, snap_args->brickorder);
6065
    } else {
6066
        keylen = snprintf(key, sizeof(key), "clone%d.brick%d.status",
6067
                          snap_args->volcount, snap_args->brickorder);
6068
        clone = 1;
6069
    }
6070

6071
    ret = glusterd_take_brick_snapshot(
6072
        snap_args->dict, snap_args->snap_vol, snap_args->brickinfo,
6073
        snap_args->volcount, snap_args->brickorder, clone);
6074

6075
    if (ret) {
6076
        gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6077
               "Failed to "
6078
               "take backend snapshot for brick "
6079
               "%s:%s volume(%s)",
6080
               snap_args->brickinfo->hostname, snap_args->brickinfo->path,
6081
               snap_args->snap_vol->volname);
6082
    }
6083

6084
    if (dict_set_int32n(snap_args->rsp_dict, key, keylen, (ret) ? 0 : 1)) {
6085
        gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6086
               "failed to "
6087
               "add %s to dict",
6088
               key);
6089
        ret = -1;
6090
        goto out;
6091
    }
6092

6093
out:
6094
    return ret;
6095
}
6096

6097
int32_t
6098
glusterd_take_brick_snapshot_cbk(int ret, call_frame_t *frame, void *opaque)
6099
{
6100
    snap_create_args_t *snap_args = NULL;
6101
    struct syncargs *args = NULL;
6102

6103
    GF_ASSERT(opaque);
6104

6105
    snap_args = (snap_create_args_t *)opaque;
6106
    args = snap_args->args;
6107

6108
    if (ret)
6109
        args->op_ret = ret;
6110

6111
    GF_FREE(opaque);
6112
    synctask_barrier_wake(args);
6113
    return 0;
6114
}
6115

6116
int32_t
6117
glusterd_schedule_brick_snapshot(dict_t *dict, dict_t *rsp_dict,
6118
                                 glusterd_snap_t *snap)
6119
{
6120
    int ret = -1;
6121
    int32_t volcount = 0;
6122
    int32_t brickcount = 0;
6123
    int32_t brickorder = 0;
6124
    int32_t taskcount = 0;
6125
    char key[64] = "";
6126
    int keylen;
6127
    xlator_t *this = THIS;
6128
    glusterd_volinfo_t *snap_vol = NULL;
6129
    glusterd_brickinfo_t *brickinfo = NULL;
6130
    struct syncargs args = {0};
6131
    snap_create_args_t *snap_args = NULL;
6132

6133
    GF_ASSERT(dict);
6134
    GF_ASSERT(snap);
6135

6136
    ret = synctask_barrier_init((&args));
6137
    if (ret)
6138
        goto out;
6139
    cds_list_for_each_entry(snap_vol, &snap->volumes, vol_list)
6140
    {
6141
        volcount++;
6142
        brickcount = 0;
6143
        brickorder = 0;
6144
        cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
6145
        {
6146
            keylen = snprintf(key, sizeof(key), "snap-vol%d.brick%d.order",
6147
                              volcount, brickcount);
6148
            ret = dict_set_int32n(rsp_dict, key, keylen, brickorder);
6149
            if (ret) {
6150
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6151
                       "Failed to set %s", key);
6152
                goto out;
6153
            }
6154

6155
            if ((gf_uuid_compare(brickinfo->uuid, MY_UUID)) ||
6156
                (brickinfo->snap_status == -1)) {
6157
                if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
6158
                    brickcount++;
6159
                    keylen = snprintf(key, sizeof(key),
6160
                                      "snap-vol%d.brick%d.status", volcount,
6161
                                      brickorder);
6162
                    ret = dict_set_int32n(rsp_dict, key, keylen, 0);
6163
                    if (ret) {
6164
                        gf_msg(this->name, GF_LOG_ERROR, 0,
6165
                               GD_MSG_DICT_SET_FAILED,
6166
                               "failed to add %s to "
6167
                               "dict",
6168
                               key);
6169
                        goto out;
6170
                    }
6171
                }
6172
                brickorder++;
6173
                continue;
6174
            }
6175

6176
            snap_args = GF_CALLOC(1, sizeof(*snap_args),
6177
                                  gf_gld_mt_snap_create_args_t);
6178
            if (!snap_args) {
6179
                ret = -1;
6180
                goto out;
6181
            }
6182

6183
            snap_args->this = this;
6184
            snap_args->dict = dict;
6185
            snap_args->rsp_dict = rsp_dict;
6186
            snap_args->snap_vol = snap_vol;
6187
            snap_args->brickinfo = brickinfo;
6188
            snap_args->volcount = volcount;
6189
            snap_args->brickcount = brickcount;
6190
            snap_args->brickorder = brickorder;
6191
            snap_args->args = &args;
6192

6193
            ret = synctask_new(
6194
                this->ctx->env, glusterd_take_brick_snapshot_task,
6195
                glusterd_take_brick_snapshot_cbk, NULL, snap_args);
6196
            if (ret) {
6197
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6198
                       "Failed to "
6199
                       "spawn task for snapshot create");
6200
                GF_FREE(snap_args);
6201
                goto out;
6202
            }
6203
            taskcount++;
6204
            brickcount++;
6205
            brickorder++;
6206
        }
6207

6208
        snprintf(key, sizeof(key), "snap-vol%d_brickcount", volcount);
6209
        ret = dict_set_int64(rsp_dict, key, brickcount);
6210
        if (ret) {
6211
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6212
                   "failed to "
6213
                   "add %s to dict",
6214
                   key);
6215
            goto out;
6216
        }
6217
    }
6218
    synctask_barrier_wait((&args), taskcount);
6219
    taskcount = 0;
6220

6221
    if (args.op_ret)
6222
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6223
               "Failed to create snapshot");
6224

6225
    ret = args.op_ret;
6226
out:
6227
    if (ret && taskcount)
6228
        synctask_barrier_wait((&args), taskcount);
6229

6230
    return ret;
6231
}
6232

6233
glusterd_snap_t *
6234
glusterd_create_snap_object_for_clone(dict_t *dict, dict_t *rsp_dict)
6235
{
6236
    char *snapname = NULL;
6237
    uuid_t *snap_id = NULL;
6238
    glusterd_snap_t *snap = NULL;
6239
    xlator_t *this = THIS;
6240
    int ret = -1;
6241

6242
    GF_ASSERT(dict);
6243
    GF_ASSERT(rsp_dict);
6244

6245
    /* Fetch snapname, description, id and time from dict */
6246
    ret = dict_get_str(dict, "clonename", &snapname);
6247
    if (ret) {
6248
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6249
               "Unable to fetch clonename");
6250
        goto out;
6251
    }
6252

6253
    ret = dict_get_bin(dict, "clone-id", (void **)&snap_id);
6254
    if (ret) {
6255
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6256
               "Unable to fetch clone_id");
6257
        goto out;
6258
    }
6259

6260
    snap = glusterd_new_snap_object();
6261
    if (!snap) {
6262
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJ_NEW_FAIL,
6263
               "Could not create "
6264
               "the snap object for snap %s",
6265
               snapname);
6266
        goto out;
6267
    }
6268

6269
    gf_strncpy(snap->snapname, snapname, sizeof(snap->snapname));
6270
    gf_uuid_copy(snap->snap_id, *snap_id);
6271

6272
    ret = 0;
6273

6274
out:
6275
    if (ret) {
6276
        snap = NULL;
6277
    }
6278

6279
    return snap;
6280
}
6281

6282
int32_t
6283
glusterd_snapshot_clone_commit(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
6284
{
6285
    int ret = -1;
6286
    int64_t volcount = 0;
6287
    char *snapname = NULL;
6288
    char *volname = NULL;
6289
    char *tmp_name = NULL;
6290
    xlator_t *this = THIS;
6291
    glusterd_snap_t *snap_parent = NULL;
6292
    glusterd_snap_t *snap = NULL;
6293
    glusterd_volinfo_t *origin_vol = NULL;
6294
    glusterd_volinfo_t *snap_vol = NULL;
6295
    glusterd_conf_t *priv = NULL;
6296
    char parent_snap_volume_id[64] = "";
6297

6298
    GF_ASSERT(dict);
6299
    GF_ASSERT(op_errstr);
6300
    GF_ASSERT(rsp_dict);
6301
    priv = this->private;
6302
    GF_ASSERT(priv);
6303

6304
    ret = dict_get_str(dict, "clonename", &snapname);
6305
    if (ret) {
6306
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6307
               "Unable to fetch clonename");
6308
        goto out;
6309
    }
6310
    tmp_name = gf_strdup(snapname);
6311
    if (!tmp_name) {
6312
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
6313
               "Out of memory");
6314
        ret = -1;
6315
        goto out;
6316
    }
6317

6318
    ret = dict_set_dynstr(rsp_dict, "clonename", tmp_name);
6319
    if (ret) {
6320
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6321
               "Unable to set clonename in rsp_dict");
6322
        GF_FREE(tmp_name);
6323
        goto out;
6324
    }
6325
    tmp_name = NULL;
6326

6327
    ret = dict_get_str(dict, "snapname", &volname);
6328
    if (ret) {
6329
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6330
               "failed to get snap name");
6331
        goto out;
6332
    }
6333

6334
    snap_parent = glusterd_find_snap_by_name(volname);
6335
    if (!snap_parent) {
6336
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
6337
               "Failed to "
6338
               "fetch snap %s",
6339
               volname);
6340
        goto out;
6341
    }
6342

6343
    /* TODO : As of now there is only one volume in snapshot.
6344
     * Change this when multiple volume snapshot is introduced
6345
     */
6346
    origin_vol = cds_list_entry(snap_parent->volumes.next, glusterd_volinfo_t,
6347
                                vol_list);
6348
    if (!origin_vol) {
6349
        gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
6350
               "Failed to get snap "
6351
               "volinfo %s",
6352
               snap_parent->snapname);
6353
        goto out;
6354
    }
6355

6356
    snap = glusterd_create_snap_object_for_clone(dict, rsp_dict);
6357
    if (!snap) {
6358
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJ_NEW_FAIL,
6359
               "creating the"
6360
               "snap object %s failed",
6361
               snapname);
6362
        ret = -1;
6363
        goto out;
6364
    }
6365

6366
    /* Update Parent Snapname and Volume Id for Clone */
6367
    ret = dict_set_dynstr_with_alloc(dict, "parent_snapname",
6368
                                     snap_parent->snapname);
6369
    if (ret) {
6370
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6371
               "Unable to store "
6372
               "parent snapname for %s",
6373
               volname);
6374
        goto out;
6375
    }
6376

6377
    GLUSTERD_GET_UUID_NOHYPHEN(parent_snap_volume_id, origin_vol->volume_id);
6378

6379
    ret = dict_set_dynstr_with_alloc(dict, "parent_snap_volume_id",
6380
                                     parent_snap_volume_id);
6381
    if (ret) {
6382
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6383
               "Unable to store "
6384
               "parent snapname for %s",
6385
               volname);
6386
        goto out;
6387
    }
6388

6389
    snap_vol = glusterd_do_snap_vol(origin_vol, snap, dict, rsp_dict, 1, 1);
6390
    if (!snap_vol) {
6391
        ret = -1;
6392
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
6393
               "taking the "
6394
               "snapshot of the volume %s failed",
6395
               volname);
6396
        goto out;
6397
    }
6398

6399
    volcount = 1;
6400
    ret = dict_set_int64(rsp_dict, "volcount", volcount);
6401
    if (ret) {
6402
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6403
               "Failed to set volcount");
6404
        goto out;
6405
    }
6406

6407
    ret = glusterd_schedule_brick_snapshot(dict, rsp_dict, snap);
6408
    if (ret) {
6409
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_BACKEND_MAKE_FAIL,
6410
               "Failed to take backend "
6411
               "snapshot %s",
6412
               snap->snapname);
6413
        goto out;
6414
    }
6415

6416
    cds_list_del_init(&snap_vol->vol_list);
6417
    ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
6418
                                     uuid_utoa(snap_vol->volume_id));
6419
    if (ret) {
6420
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6421
               "Failed to set snap "
6422
               "uuid in response dictionary for %s snapshot",
6423
               snap->snapname);
6424
        goto out;
6425
    }
6426

6427
    glusterd_list_add_order(&snap_vol->vol_list, &priv->volumes,
6428
                            glusterd_compare_volume_name);
6429

6430
    ret = 0;
6431

6432
out:
6433
    if (ret) {
6434
        if (snap)
6435
            glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_true);
6436
        snap = NULL;
6437
    }
6438

6439
    gf_msg_trace(this->name, 0, "Returning %d", ret);
6440
    return ret;
6441
}
6442

6443
int32_t
6444
glusterd_snapshot_create_commit(dict_t *dict, char **op_errstr,
6445
                                uint32_t *op_errno, dict_t *rsp_dict)
6446
{
6447
    int ret = -1;
6448
    int64_t i = 0;
6449
    int64_t volcount = 0;
6450
    int32_t snap_activate = 0;
6451
    int32_t flags = 0;
6452
    char *snapname = NULL;
6453
    char *volname = NULL;
6454
    char *tmp_name = NULL;
6455
    char key[64] = "";
6456
    int keylen;
6457
    xlator_t *this = THIS;
6458
    glusterd_snap_t *snap = NULL;
6459
    glusterd_volinfo_t *origin_vol = NULL;
6460
    glusterd_volinfo_t *snap_vol = NULL;
6461
    glusterd_conf_t *priv = NULL;
6462

6463
    GF_ASSERT(dict);
6464
    GF_ASSERT(op_errstr);
6465
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
6466
    GF_ASSERT(rsp_dict);
6467
    priv = this->private;
6468
    GF_ASSERT(priv);
6469

6470
    ret = dict_get_int64(dict, "volcount", &volcount);
6471
    if (ret) {
6472
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6473
               "failed to "
6474
               "get the volume count");
6475
        goto out;
6476
    }
6477

6478
    ret = dict_get_str(dict, "snapname", &snapname);
6479
    if (ret) {
6480
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6481
               "Unable to fetch snapname");
6482
        goto out;
6483
    }
6484
    tmp_name = gf_strdup(snapname);
6485
    if (!tmp_name) {
6486
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
6487
               "Out of memory");
6488
        ret = -1;
6489
        goto out;
6490
    }
6491

6492
    ret = dict_set_dynstr(rsp_dict, "snapname", tmp_name);
6493
    if (ret) {
6494
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6495
               "Unable to set snapname in rsp_dict");
6496
        GF_FREE(tmp_name);
6497
        goto out;
6498
    }
6499
    tmp_name = NULL;
6500

6501
    snap = glusterd_create_snap_object(dict, rsp_dict);
6502
    if (!snap) {
6503
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6504
               "creating the"
6505
               "snap object %s failed",
6506
               snapname);
6507
        ret = -1;
6508
        goto out;
6509
    }
6510

6511
    for (i = 1; i <= volcount; i++) {
6512
        keylen = snprintf(key, sizeof(key), "volname%" PRId64, i);
6513
        ret = dict_get_strn(dict, key, keylen, &volname);
6514
        if (ret) {
6515
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6516
                   "failed to get volume name");
6517
            goto out;
6518
        }
6519

6520
        ret = glusterd_volinfo_find(volname, &origin_vol);
6521
        if (ret) {
6522
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
6523
                   "failed to get the volinfo for "
6524
                   "the volume %s",
6525
                   volname);
6526
            goto out;
6527
        }
6528

6529
        if (is_origin_glusterd(dict)) {
6530
            ret = glusterd_is_snap_soft_limit_reached(origin_vol, rsp_dict);
6531
            if (ret) {
6532
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED,
6533
                       "Failed to "
6534
                       "check soft limit exceeded or not, "
6535
                       "for volume %s ",
6536
                       origin_vol->volname);
6537
                goto out;
6538
            }
6539
        }
6540

6541
        snap_vol = glusterd_do_snap_vol(origin_vol, snap, dict, rsp_dict, i, 0);
6542
        if (!snap_vol) {
6543
            ret = -1;
6544
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
6545
                   "taking the "
6546
                   "snapshot of the volume %s failed",
6547
                   volname);
6548
            goto out;
6549
        }
6550
    }
6551
    ret = dict_set_int64(rsp_dict, "volcount", volcount);
6552
    if (ret) {
6553
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6554
               "Failed to set volcount");
6555
        goto out;
6556
    }
6557

6558
    ret = glusterd_schedule_brick_snapshot(dict, rsp_dict, snap);
6559
    if (ret) {
6560
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6561
               "Failed to take backend "
6562
               "snapshot %s",
6563
               snap->snapname);
6564
        goto out;
6565
    }
6566

6567
    ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
6568
                                     uuid_utoa(snap->snap_id));
6569
    if (ret) {
6570
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6571
               "Failed to set snap "
6572
               "uuid in response dictionary for %s snapshot",
6573
               snap->snapname);
6574
        goto out;
6575
    }
6576

6577
    snap_activate = dict_get_str_boolean(
6578
        priv->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, _gf_false);
6579
    if (!snap_activate) {
6580
        cds_list_for_each_entry(snap_vol, &snap->volumes, vol_list)
6581
        {
6582
            snap_vol->status = GLUSTERD_STATUS_STOPPED;
6583
            ret = glusterd_store_volinfo(snap_vol,
6584
                                         GLUSTERD_VOLINFO_VER_AC_INCREMENT);
6585
            if (ret) {
6586
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_SET_FAIL,
6587
                       "Failed to store snap volinfo %s", snap_vol->volname);
6588
                goto out;
6589
            }
6590
        }
6591

6592
        goto out;
6593
    }
6594

6595
    /* Activate created bricks in case of activate-on-create config. */
6596
    ret = dict_get_int32(dict, "flags", &flags);
6597
    if (ret) {
6598
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6599
               "Unable to get flags");
6600
        goto out;
6601
    }
6602

6603
    cds_list_for_each_entry(snap_vol, &snap->volumes, vol_list)
6604
    {
6605
        ret = glusterd_start_volume(snap_vol, flags, _gf_true);
6606
        if (ret) {
6607
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
6608
                   "Failed to activate snap volume %s of the "
6609
                   "snap %s",
6610
                   snap_vol->volname, snap->snapname);
6611
            goto out;
6612
        }
6613
    }
6614

6615
    ret = 0;
6616

6617
out:
6618
    if (ret) {
6619
        if (snap)
6620
            glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_false);
6621
        snap = NULL;
6622
    }
6623

6624
    gf_msg_trace(this->name, 0, "Returning %d", ret);
6625
    return ret;
6626
}
6627

6628
int
6629
snap_max_hard_limit_set_commit(dict_t *dict, uint64_t value, char *volname,
6630
                               char **op_errstr)
6631
{
6632
    char err_str[PATH_MAX] = "";
6633
    glusterd_conf_t *conf = NULL;
6634
    glusterd_volinfo_t *volinfo = NULL;
6635
    int ret = -1;
6636
    xlator_t *this = THIS;
6637
    char *next_version = NULL;
6638

6639
    GF_ASSERT(dict);
6640
    GF_ASSERT(op_errstr);
6641

6642
    conf = this->private;
6643

6644
    GF_ASSERT(conf);
6645

6646
    /* TODO: Initiate auto deletion when there is a limit change */
6647
    if (!volname) {
6648
        /* For system limit */
6649
        ret = dict_set_uint64(conf->opts,
6650
                              GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, value);
6651
        if (ret) {
6652
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6653
                   "Failed to store "
6654
                   "%s in the options",
6655
                   GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
6656
            goto out;
6657
        }
6658

6659
        ret = glusterd_get_next_global_opt_version_str(conf->opts,
6660
                                                       &next_version);
6661
        if (ret)
6662
            goto out;
6663

6664
        ret = dict_set_str_sizen(conf->opts, GLUSTERD_GLOBAL_OPT_VERSION,
6665
                                 next_version);
6666
        if (ret)
6667
            goto out;
6668

6669
        ret = glusterd_store_options(this, conf->opts);
6670
        if (ret) {
6671
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_FAIL,
6672
                   "Failed to store "
6673
                   "options");
6674
            goto out;
6675
        }
6676
    } else {
6677
        /*  For one volume */
6678
        ret = glusterd_volinfo_find(volname, &volinfo);
6679
        if (ret) {
6680
            snprintf(err_str, PATH_MAX,
6681
                     "Failed to get the"
6682
                     " volinfo for volume %s",
6683
                     volname);
6684
            goto out;
6685
        }
6686

6687
        volinfo->snap_max_hard_limit = value;
6688

6689
        ret = glusterd_store_volinfo(volinfo,
6690
                                     GLUSTERD_VOLINFO_VER_AC_INCREMENT);
6691
        if (ret) {
6692
            snprintf(err_str, PATH_MAX,
6693
                     "Failed to store "
6694
                     "snap-max-hard-limit for volume %s",
6695
                     volname);
6696
            goto out;
6697
        }
6698
    }
6699

6700
    ret = 0;
6701
out:
6702
    if (ret) {
6703
        *op_errstr = gf_strdup(err_str);
6704
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
6705
               err_str);
6706
    }
6707
    return ret;
6708
}
6709

6710
int
6711
glusterd_snapshot_config_commit(dict_t *dict, char **op_errstr,
6712
                                dict_t *rsp_dict)
6713
{
6714
    char *volname = NULL;
6715
    xlator_t *this = THIS;
6716
    int ret = -1;
6717
    glusterd_conf_t *conf = NULL;
6718
    int config_command = 0;
6719
    uint64_t hard_limit = 0;
6720
    uint64_t soft_limit = 0;
6721
    char *next_version = NULL;
6722
    char *auto_delete = NULL;
6723
    char *snap_activate = NULL;
6724
    gf_boolean_t system_conf = _gf_false;
6725

6726
    GF_ASSERT(dict);
6727
    GF_ASSERT(op_errstr);
6728

6729
    conf = this->private;
6730

6731
    GF_ASSERT(conf);
6732

6733
    ret = dict_get_int32(dict, "config-command", &config_command);
6734
    if (ret) {
6735
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
6736
               "failed to get config-command type");
6737
        goto out;
6738
    }
6739
    if (config_command != GF_SNAP_CONFIG_TYPE_SET) {
6740
        ret = 0;
6741
        goto out;
6742
    }
6743

6744
    ret = dict_get_str(dict, "volname", &volname);
6745

6746
    /* config values snap-max-hard-limit and snap-max-soft-limit are
6747
     * optional and hence we are not erroring out if values are not
6748
     * present
6749
     */
6750
    gd_get_snap_conf_values_if_present(dict, &hard_limit, &soft_limit);
6751

6752
    if (hard_limit) {
6753
        /* Commit ops for snap-max-hard-limit */
6754
        ret = snap_max_hard_limit_set_commit(dict, hard_limit, volname,
6755
                                             op_errstr);
6756
        if (ret) {
6757
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HARD_LIMIT_SET_FAIL,
6758
                   "snap-max-hard-limit set commit failed.");
6759
            goto out;
6760
        }
6761
    }
6762

6763
    if (soft_limit) {
6764
        /* For system limit */
6765
        system_conf = _gf_true;
6766
        ret = dict_set_uint64(
6767
            conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, soft_limit);
6768
        if (ret) {
6769
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6770
                   "Failed to save %s in the dictionary",
6771
                   GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT);
6772
            goto out;
6773
        }
6774
    }
6775

6776
    if (hard_limit || soft_limit) {
6777
        ret = 0;
6778
        goto done;
6779
    }
6780

6781
    if (!dict_get_str(dict, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE,
6782
                      &auto_delete)) {
6783
        system_conf = _gf_true;
6784
        ret = dict_set_dynstr_with_alloc(
6785
            conf->opts, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, auto_delete);
6786
        if (ret) {
6787
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6788
                   "Could not "
6789
                   "save auto-delete value in conf->opts");
6790
            goto out;
6791
        }
6792
    } else if (!dict_get_str(dict, GLUSTERD_STORE_KEY_SNAP_ACTIVATE,
6793
                             &snap_activate)) {
6794
        system_conf = _gf_true;
6795
        ret = dict_set_dynstr_with_alloc(
6796
            conf->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, snap_activate);
6797
        if (ret) {
6798
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6799
                   "Could not save "
6800
                   "snap-activate-on-create value in conf->opts");
6801
            goto out;
6802
        }
6803
    } else {
6804
        ret = -1;
6805
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
6806
               "Invalid option");
6807
        goto out;
6808
    }
6809

6810
done:
6811
    if (system_conf) {
6812
        ret = glusterd_get_next_global_opt_version_str(conf->opts,
6813
                                                       &next_version);
6814
        if (ret) {
6815
            gf_msg(this->name, GF_LOG_ERROR, 0,
6816
                   GD_MSG_GLOBAL_OP_VERSION_GET_FAIL,
6817
                   "Failed to get next global opt-version");
6818
            goto out;
6819
        }
6820

6821
        ret = dict_set_str_sizen(conf->opts, GLUSTERD_GLOBAL_OPT_VERSION,
6822
                                 next_version);
6823
        if (ret) {
6824
            gf_msg(this->name, GF_LOG_ERROR, 0,
6825
                   GD_MSG_GLOBAL_OP_VERSION_SET_FAIL,
6826
                   "Failed to set next global opt-version");
6827
            goto out;
6828
        }
6829

6830
        ret = glusterd_store_options(this, conf->opts);
6831
        if (ret) {
6832
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_FAIL,
6833
                   "Failed to store options");
6834
            goto out;
6835
        }
6836
    }
6837

6838
out:
6839
    gf_msg_trace(this->name, 0, "Returning %d", ret);
6840
    return ret;
6841
}
6842

6843
static int
6844
glusterd_get_single_brick_status(char **op_errstr, dict_t *rsp_dict,
6845
                                 const char *keyprefix, int index,
6846
                                 glusterd_volinfo_t *snap_volinfo,
6847
                                 glusterd_brickinfo_t *brickinfo)
6848
{
6849
    int ret = -1;
6850
    xlator_t *this = THIS;
6851
    glusterd_conf_t *priv = NULL;
6852
    char key[128] = ""; /* keyprefix is not longer than 64 bytes */
6853
    int keylen;
6854
    char *value = NULL;
6855
    char brick_path[PATH_MAX] = "";
6856
    char pidfile[PATH_MAX] = "";
6857
    pid_t pid = -1;
6858
    struct glusterd_snap_ops *snap_ops = NULL;
6859

6860
    priv = this->private;
6861
    GF_ASSERT(priv);
6862

6863
    GF_ASSERT(op_errstr);
6864
    GF_ASSERT(rsp_dict);
6865
    GF_ASSERT(keyprefix);
6866
    GF_ASSERT(snap_volinfo);
6867
    GF_ASSERT(brickinfo);
6868

6869
    keylen = snprintf(key, sizeof(key), "%s.brick%d.path", keyprefix, index);
6870
    if (keylen < 0) {
6871
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
6872
        ret = -1;
6873
        goto out;
6874
    }
6875

6876
    ret = snprintf(brick_path, sizeof(brick_path), "%s:%s", brickinfo->hostname,
6877
                   brickinfo->path);
6878
    if (ret < 0) {
6879
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
6880
        goto out;
6881
    }
6882

6883
    value = gf_strdup(brick_path);
6884
    if (!value) {
6885
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_STRDUP_FAILED,
6886
                "brick_path=%s", brick_path, NULL);
6887
        ret = -1;
6888
        goto out;
6889
    }
6890

6891
    ret = dict_set_dynstrn(rsp_dict, key, keylen, value);
6892
    if (ret) {
6893
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6894
               "Unable to store "
6895
               "brick_path %s",
6896
               brickinfo->path);
6897
        goto out;
6898
    }
6899

6900
    if (brickinfo->snap_status == -1) {
6901
        /* Setting vgname as "Pending Snapshot" */
6902
        value = gf_strdup("Pending Snapshot");
6903
        if (!value) {
6904
            ret = -1;
6905
            goto out;
6906
        }
6907

6908
        keylen = snprintf(key, sizeof(key), "%s.brick%d.vgname", keyprefix,
6909
                          index);
6910
        ret = dict_set_dynstrn(rsp_dict, key, keylen, value);
6911
        if (ret) {
6912
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6913
                   "Could not save vgname ");
6914
            goto out;
6915
        }
6916

6917
        ret = 0;
6918
        goto out;
6919
    }
6920
    value = NULL;
6921

6922
    keylen = snprintf(key, sizeof(key), "%s.brick%d.status", keyprefix, index);
6923
    if (keylen < 0) {
6924
        ret = -1;
6925
        goto out;
6926
    }
6927

6928
    if (brickinfo->status == GF_BRICK_STOPPED) {
6929
        value = gf_strdup("No");
6930
        if (!value) {
6931
            ret = -1;
6932
            goto out;
6933
        }
6934
        ret = dict_set_strn(rsp_dict, key, keylen, value);
6935
        if (ret) {
6936
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6937
                   "Could not save brick status");
6938
            goto out;
6939
        }
6940
        value = NULL;
6941
    } else {
6942
        value = gf_strdup("Yes");
6943
        if (!value) {
6944
            ret = -1;
6945
            goto out;
6946
        }
6947
        ret = dict_set_strn(rsp_dict, key, keylen, value);
6948
        if (ret) {
6949
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6950
                   "Could not save brick status");
6951
            goto out;
6952
        }
6953
        value = NULL;
6954

6955
        GLUSTERD_GET_BRICK_PIDFILE(pidfile, snap_volinfo, brickinfo, priv);
6956

6957
        if (gf_is_service_running(pidfile, &pid)) {
6958
            keylen = snprintf(key, sizeof(key), "%s.brick%d.pid", keyprefix,
6959
                              index);
6960
            if (keylen < 0) {
6961
                ret = -1;
6962
                gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL,
6963
                        NULL);
6964
                goto out;
6965
            }
6966

6967
            ret = dict_set_int32n(rsp_dict, key, keylen, pid);
6968
            if (ret) {
6969
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6970
                       "Could not save pid %d", pid);
6971
                goto out;
6972
            }
6973
        }
6974
    }
6975

6976
    keylen = snprintf(key, sizeof(key), "%s.brick%d", keyprefix, index);
6977
    if (keylen < 0) {
6978
        ret = -1;
6979
        goto out;
6980
    }
6981
    /* While getting snap status we should show relevant information
6982
     * for deactivated snaps.
6983
     */
6984
    if (snap_volinfo->status == GLUSTERD_STATUS_STOPPED) {
6985
        /* Setting vgname as "Deactivated Snapshot" */
6986
        value = gf_strdup("N/A (Deactivated Snapshot)");
6987
        if (!value) {
6988
            ret = -1;
6989
            goto out;
6990
        }
6991

6992
        keylen = snprintf(key, sizeof(key), "%s.brick%d.vgname", keyprefix,
6993
                          index);
6994
        ret = dict_set_dynstrn(rsp_dict, key, keylen, value);
6995
        if (ret) {
6996
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6997
                   "Could not save vgname ");
6998
            goto out;
6999
        }
7000

7001
        ret = 0;
7002
        goto out;
7003
    }
7004

7005
    glusterd_snapshot_plugin_by_name(snap_volinfo->snap_plugin, &snap_ops);
7006

7007
    ret = snap_ops->details(rsp_dict, brickinfo,
7008
                            snap_volinfo->snapshot->snapname,
7009
                            snap_volinfo->volname, index, key);
7010

7011
    if (ret) {
7012
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_GET_INFO_FAIL,
7013
               "Failed to get "
7014
               "brick details");
7015
        goto out;
7016
    }
7017
out:
7018
    if (ret && value) {
7019
        GF_FREE(value);
7020
    }
7021

7022
    return ret;
7023
}
7024

7025
static int
7026
glusterd_get_single_snap_status(char **op_errstr, dict_t *rsp_dict,
7027
                                const char *keyprefix, glusterd_snap_t *snap)
7028
{
7029
    int ret = -1;
7030
    xlator_t *this = THIS;
7031
    char key[64] = ""; /* keyprefix is "status.snap0" */
7032
    int keylen;
7033
    char brickkey[PATH_MAX] = "";
7034
    glusterd_volinfo_t *snap_volinfo = NULL;
7035
    glusterd_volinfo_t *tmp_volinfo = NULL;
7036
    glusterd_brickinfo_t *brickinfo = NULL;
7037
    int volcount = 0;
7038
    int brickcount = 0;
7039

7040
    GF_ASSERT(op_errstr);
7041
    GF_ASSERT(rsp_dict);
7042
    GF_ASSERT(keyprefix);
7043
    GF_ASSERT(snap);
7044

7045
    cds_list_for_each_entry_safe(snap_volinfo, tmp_volinfo, &snap->volumes,
7046
                                 vol_list)
7047
    {
7048
        keylen = snprintf(key, sizeof(key), "%s.vol%d", keyprefix, volcount);
7049
        if (keylen < 0) {
7050
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7051
            ret = -1;
7052
            goto out;
7053
        }
7054
        cds_list_for_each_entry(brickinfo, &snap_volinfo->bricks, brick_list)
7055
        {
7056
            if (!glusterd_is_local_brick(snap_volinfo, brickinfo)) {
7057
                brickcount++;
7058
                continue;
7059
            }
7060

7061
            ret = glusterd_get_single_brick_status(
7062
                op_errstr, rsp_dict, key, brickcount, snap_volinfo, brickinfo);
7063

7064
            if (ret) {
7065
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7066
                       "Getting "
7067
                       "single snap status failed");
7068
                goto out;
7069
            }
7070
            brickcount++;
7071
        }
7072
        keylen = snprintf(brickkey, sizeof(brickkey), "%s.brickcount", key);
7073
        if (keylen < 0) {
7074
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7075
            goto out;
7076
        }
7077

7078
        ret = dict_set_int32n(rsp_dict, brickkey, keylen, brickcount);
7079
        if (ret) {
7080
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7081
                   "Could not save brick count");
7082
            goto out;
7083
        }
7084
        volcount++;
7085
    }
7086

7087
    keylen = snprintf(key, sizeof(key), "%s.volcount", keyprefix);
7088
    if (keylen < 0) {
7089
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7090
        ret = -1;
7091
        goto out;
7092
    }
7093

7094
    ret = dict_set_int32n(rsp_dict, key, keylen, volcount);
7095
    if (ret) {
7096
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7097
               "Could not save volcount");
7098
        goto out;
7099
    }
7100

7101
out:
7102

7103
    return ret;
7104
}
7105

7106
static int
7107
glusterd_get_each_snap_object_status(char **op_errstr, dict_t *rsp_dict,
7108
                                     glusterd_snap_t *snap,
7109
                                     const char *keyprefix)
7110
{
7111
    int ret = -1;
7112
    char key[32] = ""; /* keyprefix is "status.snap0" */
7113
    int keylen;
7114
    char *temp = NULL;
7115
    xlator_t *this = THIS;
7116

7117
    GF_ASSERT(op_errstr);
7118
    GF_ASSERT(rsp_dict);
7119
    GF_ASSERT(snap);
7120
    GF_ASSERT(keyprefix);
7121

7122
    /* TODO : Get all the snap volume info present in snap object,
7123
     * as of now, There will be only one snapvolinfo per snap object
7124
     */
7125
    keylen = snprintf(key, sizeof(key), "%s.snapname", keyprefix);
7126
    if (keylen < 0) {
7127
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7128
        ret = -1;
7129
        goto out;
7130
    }
7131

7132
    temp = gf_strdup(snap->snapname);
7133
    if (temp == NULL) {
7134
        ret = -1;
7135
        goto out;
7136
    }
7137
    ret = dict_set_dynstrn(rsp_dict, key, keylen, temp);
7138
    if (ret) {
7139
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7140
               "Could not save "
7141
               "snap name");
7142
        goto out;
7143
    }
7144

7145
    temp = NULL;
7146

7147
    keylen = snprintf(key, sizeof(key), "%s.uuid", keyprefix);
7148
    if (keylen < 0) {
7149
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7150
        ret = -1;
7151
        goto out;
7152
    }
7153

7154
    temp = gf_strdup(uuid_utoa(snap->snap_id));
7155
    if (temp == NULL) {
7156
        ret = -1;
7157
        goto out;
7158
    }
7159

7160
    ret = dict_set_dynstrn(rsp_dict, key, keylen, temp);
7161
    if (ret) {
7162
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7163
               "Could not save "
7164
               "snap UUID");
7165
        goto out;
7166
    }
7167

7168
    temp = NULL;
7169

7170
    ret = glusterd_get_single_snap_status(op_errstr, rsp_dict, keyprefix, snap);
7171
    if (ret) {
7172
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7173
               "Could not get single snap status");
7174
        goto out;
7175
    }
7176

7177
    keylen = snprintf(key, sizeof(key), "%s.volcount", keyprefix);
7178
    if (keylen < 0) {
7179
        ret = keylen;
7180
        goto out;
7181
    }
7182

7183
    ret = dict_set_int32n(rsp_dict, key, keylen, 1);
7184
    if (ret) {
7185
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7186
               "Could not save volcount");
7187
        goto out;
7188
    }
7189
out:
7190
    if (ret && temp)
7191
        GF_FREE(temp);
7192

7193
    return ret;
7194
}
7195

7196
int
7197
glusterd_get_snap_status_of_volume(char **op_errstr, dict_t *rsp_dict,
7198
                                   char *volname, char *keyprefix)
7199
{
7200
    int ret = -1;
7201
    glusterd_volinfo_t *snap_volinfo = NULL;
7202
    glusterd_volinfo_t *temp_volinfo = NULL;
7203
    glusterd_volinfo_t *volinfo = NULL;
7204
    char key[64] = "";
7205
    xlator_t *this = THIS;
7206
    glusterd_conf_t *priv = NULL;
7207
    int i = 0;
7208

7209
    priv = this->private;
7210
    GF_ASSERT(priv);
7211

7212
    GF_ASSERT(op_errstr);
7213
    GF_ASSERT(rsp_dict);
7214
    GF_ASSERT(volname);
7215
    GF_ASSERT(keyprefix);
7216

7217
    ret = glusterd_volinfo_find(volname, &volinfo);
7218
    if (ret) {
7219
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
7220
               "Failed to get volinfo of "
7221
               "volume %s",
7222
               volname);
7223
        goto out;
7224
    }
7225

7226
    cds_list_for_each_entry_safe(snap_volinfo, temp_volinfo,
7227
                                 &volinfo->snap_volumes, snapvol_list)
7228
    {
7229
        ret = snprintf(key, sizeof(key), "status.snap%d.snapname", i);
7230
        if (ret < 0) {
7231
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7232
            goto out;
7233
        }
7234

7235
        ret = dict_set_dynstr_with_alloc(rsp_dict, key,
7236
                                         snap_volinfo->snapshot->snapname);
7237
        if (ret) {
7238
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7239
                   "Could not save "
7240
                   "snap name");
7241
            goto out;
7242
        }
7243

7244
        i++;
7245
    }
7246

7247
    ret = dict_set_int32_sizen(rsp_dict, "status.snapcount", i);
7248
    if (ret) {
7249
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7250
               "Failed to save snapcount");
7251
        ret = -1;
7252
        goto out;
7253
    }
7254
out:
7255
    return ret;
7256
}
7257

7258
int
7259
glusterd_get_all_snapshot_status(dict_t *dict, char **op_errstr,
7260
                                 dict_t *rsp_dict)
7261
{
7262
    int32_t i = 0;
7263
    int ret = -1;
7264
    char key[64] = "";
7265
    glusterd_conf_t *priv = NULL;
7266
    glusterd_snap_t *snap = NULL;
7267
    glusterd_snap_t *tmp_snap = NULL;
7268
    xlator_t *this = THIS;
7269

7270
    priv = this->private;
7271
    GF_ASSERT(priv);
7272

7273
    GF_ASSERT(dict);
7274
    GF_ASSERT(op_errstr);
7275

7276
    cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
7277
    {
7278
        ret = snprintf(key, sizeof(key), "status.snap%d.snapname", i);
7279
        if (ret < 0) {
7280
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7281
            goto out;
7282
        }
7283

7284
        ret = dict_set_dynstr_with_alloc(rsp_dict, key, snap->snapname);
7285
        if (ret) {
7286
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7287
                   "Could not save "
7288
                   "snap name");
7289
            goto out;
7290
        }
7291

7292
        i++;
7293
    }
7294

7295
    ret = dict_set_int32_sizen(rsp_dict, "status.snapcount", i);
7296
    if (ret) {
7297
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7298
               "Could not save snapcount");
7299
        goto out;
7300
    }
7301

7302
    ret = 0;
7303
out:
7304
    return ret;
7305
}
7306

7307
int
7308
glusterd_snapshot_status_commit(dict_t *dict, char **op_errstr,
7309
                                dict_t *rsp_dict)
7310
{
7311
    xlator_t *this = THIS;
7312
    int ret = -1;
7313
    glusterd_conf_t *conf = NULL;
7314
    int32_t cmd = -1;
7315
    char *snapname = NULL;
7316
    glusterd_snap_t *snap = NULL;
7317
    char *volname = NULL;
7318

7319
    GF_ASSERT(dict);
7320
    GF_ASSERT(op_errstr);
7321

7322
    conf = this->private;
7323

7324
    GF_ASSERT(conf);
7325
    ret = dict_get_int32(dict, "sub-cmd", &cmd);
7326
    if (ret) {
7327
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7328
               "Failed to get status cmd type");
7329
        goto out;
7330
    }
7331

7332
    ret = dict_set_int32_sizen(rsp_dict, "sub-cmd", cmd);
7333
    if (ret) {
7334
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7335
               "Could not save status cmd in rsp dictionary");
7336
        goto out;
7337
    }
7338
    switch (cmd) {
7339
        case GF_SNAP_STATUS_TYPE_ALL: {
7340
            ret = glusterd_get_all_snapshot_status(dict, op_errstr, rsp_dict);
7341
            if (ret) {
7342
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7343
                       "Unable to "
7344
                       "get snapshot status");
7345
                goto out;
7346
            }
7347
            break;
7348
        }
7349
        case GF_SNAP_STATUS_TYPE_ITER:
7350
        case GF_SNAP_STATUS_TYPE_SNAP: {
7351
            ret = dict_get_str(dict, "snapname", &snapname);
7352
            if (ret) {
7353
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7354
                       "Unable to "
7355
                       "get snap name");
7356
                goto out;
7357
            }
7358

7359
            snap = glusterd_find_snap_by_name(snapname);
7360
            if (!snap) {
7361
                ret = gf_asprintf(op_errstr,
7362
                                  "Snapshot (%s) "
7363
                                  "does not exist",
7364
                                  snapname);
7365
                if (ret < 0) {
7366
                    goto out;
7367
                }
7368
                ret = -1;
7369
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
7370
                       "Unable to "
7371
                       "get snap volinfo");
7372
                goto out;
7373
            }
7374
            ret = glusterd_get_each_snap_object_status(op_errstr, rsp_dict,
7375
                                                       snap, "status.snap0");
7376
            if (ret) {
7377
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7378
                       "Unable to "
7379
                       "get status of snap");
7380
                goto out;
7381
            }
7382

7383
            ret = dict_set_int32_sizen(rsp_dict, "status.snapcount", 1);
7384
            if (ret) {
7385
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7386
                       "Unable to "
7387
                       "set snapcount to 1");
7388
                goto out;
7389
            }
7390
            break;
7391
        }
7392
        case GF_SNAP_STATUS_TYPE_VOL: {
7393
            ret = dict_get_str(dict, "volname", &volname);
7394
            if (ret) {
7395
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7396
                       "Unable to"
7397
                       " get volume name");
7398
                goto out;
7399
            }
7400

7401
            ret = glusterd_get_snap_status_of_volume(op_errstr, rsp_dict,
7402
                                                     volname, "status.vol0");
7403
            if (ret) {
7404
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7405
                       "Function :"
7406
                       " glusterd_get_snap_status_of_volume "
7407
                       "failed");
7408
                goto out;
7409
            }
7410
        }
7411
    }
7412
    ret = 0;
7413
out:
7414
    return ret;
7415
}
7416

7417
static int32_t
7418
glusterd_handle_snap_limit(dict_t *dict, dict_t *rsp_dict)
7419
{
7420
    int32_t ret = -1;
7421
    xlator_t *this = THIS;
7422
    glusterd_conf_t *priv = NULL;
7423
    uint64_t effective_max_limit = 0;
7424
    int64_t volcount = 0;
7425
    int i = 0;
7426
    char *volname = NULL;
7427
    char key[64] = "";
7428
    int keylen;
7429
    char msg[PATH_MAX] = "";
7430
    glusterd_volinfo_t *volinfo = NULL;
7431
    uint64_t limit = 0;
7432
    int64_t count = 0;
7433
    glusterd_snap_t *snap = NULL;
7434
    glusterd_volinfo_t *tmp_volinfo = NULL;
7435
    uint64_t opt_max_hard = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
7436
    uint64_t opt_max_soft = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT;
7437

7438
    GF_ASSERT(dict);
7439
    GF_ASSERT(rsp_dict);
7440

7441
    priv = this->private;
7442
    GF_ASSERT(priv);
7443

7444
    ret = dict_get_int64(dict, "volcount", &volcount);
7445
    if (ret) {
7446
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7447
               "failed to get the volcount");
7448
        goto out;
7449
    }
7450

7451
    for (i = 1; i <= volcount; i++) {
7452
        keylen = snprintf(key, sizeof(key), "volname%d", i);
7453
        ret = dict_get_strn(dict, key, keylen, &volname);
7454
        if (ret) {
7455
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7456
                   "failed to get the "
7457
                   "volname");
7458
            goto out;
7459
        }
7460

7461
        ret = glusterd_volinfo_find(volname, &volinfo);
7462
        if (ret) {
7463
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
7464
                   "volinfo for %s "
7465
                   "not found",
7466
                   volname);
7467
            goto out;
7468
        }
7469

7470
        /* config values snap-max-hard-limit and snap-max-soft-limit are
7471
         * optional and hence we are not erroring out if values are not
7472
         * present
7473
         */
7474
        gd_get_snap_conf_values_if_present(priv->opts, &opt_max_hard,
7475
                                           &opt_max_soft);
7476

7477
        /* The minimum of the 2 limits i.e system wide limit and
7478
           volume wide limit will be considered
7479
        */
7480
        if (volinfo->snap_max_hard_limit < opt_max_hard)
7481
            effective_max_limit = volinfo->snap_max_hard_limit;
7482
        else
7483
            effective_max_limit = opt_max_hard;
7484

7485
        limit = (opt_max_soft * effective_max_limit) / 100;
7486

7487
        count = volinfo->snap_count - limit;
7488
        if (count <= 0)
7489
            goto out;
7490

7491
        tmp_volinfo = cds_list_entry(volinfo->snap_volumes.next,
7492
                                     glusterd_volinfo_t, snapvol_list);
7493
        snap = tmp_volinfo->snapshot;
7494
        GF_ASSERT(snap);
7495

7496
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SOFT_LIMIT_REACHED,
7497
               "Soft-limit "
7498
               "(value = %" PRIu64
7499
               ") of volume %s is reached. "
7500
               "Deleting snapshot %s.",
7501
               limit, volinfo->volname, snap->snapname);
7502

7503
        snprintf(msg, sizeof(msg),
7504
                 "snapshot_name=%s;"
7505
                 "snapshot_uuid=%s",
7506
                 snap->snapname, uuid_utoa(snap->snap_id));
7507

7508
        LOCK(&snap->lock);
7509
        {
7510
            snap->snap_status = GD_SNAP_STATUS_DECOMMISSION;
7511
            ret = glusterd_store_snap(snap);
7512
            if (ret) {
7513
                gf_msg(this->name, GF_LOG_ERROR, 0,
7514
                       GD_MSG_SNAP_OBJECT_STORE_FAIL,
7515
                       "could "
7516
                       "not store snap object %s",
7517
                       snap->snapname);
7518
                goto unlock;
7519
            }
7520

7521
            ret = glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true,
7522
                                       _gf_false);
7523
            if (ret)
7524
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
7525
                       "failed to remove snap %s", snap->snapname);
7526
        }
7527
    unlock:
7528
        UNLOCK(&snap->lock);
7529
        if (is_origin_glusterd(dict) == _gf_true) {
7530
            if (ret)
7531
                gf_event(EVENT_SNAPSHOT_DELETE_FAILED, "%s", msg);
7532
            else
7533
                gf_event(EVENT_SNAPSHOT_DELETED, "%s", msg);
7534
        }
7535
    }
7536

7537
out:
7538
    return ret;
7539
}
7540

7541
int32_t
7542
glusterd_snapshot_clone_postvalidate(dict_t *dict, int32_t op_ret,
7543
                                     char **op_errstr, dict_t *rsp_dict)
7544
{
7545
    xlator_t *this = THIS;
7546
    glusterd_conf_t *priv = NULL;
7547
    int ret = -1;
7548
    int32_t cleanup = 0;
7549
    glusterd_snap_t *snap = NULL;
7550
    glusterd_volinfo_t *snap_vol = NULL;
7551
    char *clonename = NULL;
7552

7553
    GF_ASSERT(dict);
7554
    GF_ASSERT(rsp_dict);
7555

7556
    priv = this->private;
7557
    GF_ASSERT(priv);
7558

7559
    ret = dict_get_str(dict, "clonename", &clonename);
7560
    if (ret) {
7561
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7562
               "Unable to fetch "
7563
               "clonename");
7564
        goto out;
7565
    }
7566

7567
    ret = glusterd_volinfo_find(clonename, &snap_vol);
7568
    if (ret) {
7569
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
7570
               "unable to find clone "
7571
               "%s volinfo",
7572
               clonename);
7573
        goto out;
7574
    }
7575

7576
    if (snap_vol)
7577
        snap = snap_vol->snapshot;
7578
    else {
7579
        ret = -1;
7580
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
7581
               "Snapshot volume is null");
7582
        goto out;
7583
    }
7584

7585
    /* Fetch snap object from snap_vol and delete it all in case of *
7586
     * a failure, or else, just delete the snap object as it is not *
7587
     * needed in case of a clone                                    *
7588
     */
7589
    if (op_ret) {
7590
        ret = dict_get_int32(dict, "cleanup", &cleanup);
7591
        if (!ret && cleanup && snap) {
7592
            glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_true);
7593
        }
7594
        /* Irrespective of status of cleanup its better
7595
         * to return from this function. As the functions
7596
         * following this block is not required to be
7597
         * executed in case of failure scenario.
7598
         */
7599
        ret = 0;
7600
        goto out;
7601
    }
7602

7603
    ret = glusterd_snapobject_delete(snap);
7604
    if (ret) {
7605
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
7606
               "Failed to delete "
7607
               "snap object %s",
7608
               snap->snapname);
7609
        goto out;
7610
    }
7611
    snap_vol->snapshot = NULL;
7612

7613
out:
7614
    return ret;
7615
}
7616

7617
int32_t
7618
glusterd_snapshot_create_postvalidate(dict_t *dict, int32_t op_ret,
7619
                                      char **op_errstr, dict_t *rsp_dict)
7620
{
7621
    xlator_t *this = THIS;
7622
    glusterd_conf_t *priv = NULL;
7623
    int ret = -1;
7624
    int32_t cleanup = 0;
7625
    glusterd_snap_t *snap = NULL;
7626
    char *snapname = NULL;
7627
    char *volname = NULL;
7628
    glusterd_volinfo_t *volinfo = NULL;
7629
    uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
7630
    uint64_t opt_max_soft = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT;
7631
    int64_t effective_max_limit = 0;
7632
    int64_t soft_limit = 0;
7633
    int32_t snap_activate = _gf_false;
7634

7635
    GF_ASSERT(dict);
7636
    GF_ASSERT(rsp_dict);
7637

7638
    priv = this->private;
7639
    GF_ASSERT(priv);
7640

7641
    if (op_ret) {
7642
        ret = dict_get_int32(dict, "cleanup", &cleanup);
7643
        if (!ret && cleanup) {
7644
            ret = glusterd_do_snap_cleanup(dict, op_errstr, rsp_dict);
7645
            if (ret) {
7646
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CLEANUP_FAIL,
7647
                       "cleanup "
7648
                       "operation failed");
7649
                goto out;
7650
            }
7651
        }
7652
        /* Irrespective of status of cleanup its better
7653
         * to return from this function. As the functions
7654
         * following this block is not required to be
7655
         * executed in case of failure scenario.
7656
         */
7657
        ret = 0;
7658
        goto out;
7659
    }
7660

7661
    ret = dict_get_str(dict, "snapname", &snapname);
7662
    if (ret) {
7663
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7664
               "Unable to fetch "
7665
               "snapname");
7666
        goto out;
7667
    }
7668

7669
    snap = glusterd_find_snap_by_name(snapname);
7670
    if (!snap) {
7671
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
7672
               "unable to find snap "
7673
               "%s",
7674
               snapname);
7675
        goto out;
7676
    }
7677

7678
    snap->snap_status = GD_SNAP_STATUS_IN_USE;
7679
    ret = glusterd_store_snap(snap);
7680
    if (ret) {
7681
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_OBJECT_STORE_FAIL,
7682
               "Could not store snap"
7683
               "object %s",
7684
               snap->snapname);
7685
        goto out;
7686
    }
7687

7688
    ret = glusterd_snapshot_update_snaps_post_validate(dict, op_errstr,
7689
                                                       rsp_dict);
7690
    if (ret) {
7691
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
7692
               "Failed to "
7693
               "create snapshot");
7694
        goto out;
7695
    }
7696

7697
    /*
7698
     * If activate_on_create was enabled, and we have reached this  *
7699
     * section of the code, that means, that after successfully     *
7700
     * creating the snapshot, we have also successfully started the *
7701
     * snapshot bricks on all nodes. So from originator node we can *
7702
     * send EVENT_SNAPSHOT_ACTIVATED event.                         *
7703
     *                                                              *
7704
     * Also check, if hard limit and soft limit is reached in case  *
7705
     * of successfully creating the snapshot, and generate the event *
7706
     */
7707
    if (is_origin_glusterd(dict) == _gf_true) {
7708
        snap_activate = dict_get_str_boolean(
7709
            priv->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, _gf_false);
7710

7711
        if (snap_activate == _gf_true) {
7712
            gf_event(EVENT_SNAPSHOT_ACTIVATED,
7713
                     "snapshot_name=%s;"
7714
                     "snapshot_uuid=%s",
7715
                     snap->snapname, uuid_utoa(snap->snap_id));
7716
        }
7717

7718
        ret = dict_get_str(dict, "volname1", &volname);
7719
        if (ret) {
7720
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7721
                   "Failed to get volname.");
7722
            goto out;
7723
        }
7724

7725
        ret = glusterd_volinfo_find(volname, &volinfo);
7726
        if (ret) {
7727
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
7728
                   "Failed to get volinfo.");
7729
            goto out;
7730
        }
7731

7732
        /* config values snap-max-hard-limit and snap-max-soft-limit are
7733
         * optional and hence we are not erroring out if values are not
7734
         * present
7735
         */
7736
        gd_get_snap_conf_values_if_present(priv->opts, &opt_hard_max,
7737
                                           &opt_max_soft);
7738

7739
        if (volinfo->snap_max_hard_limit < opt_hard_max)
7740
            effective_max_limit = volinfo->snap_max_hard_limit;
7741
        else
7742
            effective_max_limit = opt_hard_max;
7743

7744
        /*
7745
         * Check for hard limit. If it is reached after taking *
7746
         * this snapshot, then generate event for the same. If *
7747
         * it is not reached, then check for the soft limit,   *
7748
         * and generate event accordingly.                     *
7749
         */
7750
        if (volinfo->snap_count >= effective_max_limit) {
7751
            gf_event(EVENT_SNAPSHOT_HARD_LIMIT_REACHED,
7752
                     "volume_name=%s;volume_id=%s", volname,
7753
                     uuid_utoa(volinfo->volume_id));
7754
        } else {
7755
            soft_limit = (opt_max_soft * effective_max_limit) / 100;
7756
            if (volinfo->snap_count >= soft_limit) {
7757
                gf_event(EVENT_SNAPSHOT_SOFT_LIMIT_REACHED,
7758
                         "volume_name=%s;volume_id=%s", volname,
7759
                         uuid_utoa(volinfo->volume_id));
7760
            }
7761
        }
7762
    }
7763

7764
    /* "auto-delete" might not be set by user explicitly,
7765
     * in that case it's better to consider the default value.
7766
     * Hence not erroring out if Key is not found.
7767
     */
7768
    ret = dict_get_str_boolean(priv->opts, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE,
7769
                               _gf_false);
7770
    if (_gf_true == ret) {
7771
        ret = glusterd_handle_snap_limit(dict, rsp_dict);
7772
        if (ret) {
7773
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
7774
                   "failed to remove snap");
7775
            /* ignore the errors of autodelete */
7776
            ret = 0;
7777
        }
7778
    }
7779

7780
out:
7781
    return ret;
7782
}
7783

7784
int32_t
7785
glusterd_snapshot(dict_t *dict, char **op_errstr, uint32_t *op_errno,
7786
                  dict_t *rsp_dict)
7787
{
7788
    xlator_t *this = THIS;
7789
    glusterd_conf_t *priv = NULL;
7790
    int32_t snap_command = 0;
7791
    char *snap_name = NULL;
7792
    char temp[PATH_MAX] = "";
7793
    int ret = -1;
7794

7795
    GF_ASSERT(dict);
7796
    GF_ASSERT(rsp_dict);
7797
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
7798

7799
    priv = this->private;
7800
    GF_ASSERT(priv);
7801

7802
    ret = dict_get_int32(dict, "type", &snap_command);
7803
    if (ret) {
7804
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
7805
               "unable to get the type of "
7806
               "the snapshot command");
7807
        goto out;
7808
    }
7809

7810
    switch (snap_command) {
7811
        case (GF_SNAP_OPTION_TYPE_CREATE):
7812
            ret = glusterd_snapshot_create_commit(dict, op_errstr, op_errno,
7813
                                                  rsp_dict);
7814
            if (ret) {
7815
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
7816
                       "Failed to "
7817
                       "create snapshot");
7818
                goto out;
7819
            }
7820
            break;
7821

7822
        case (GF_SNAP_OPTION_TYPE_CLONE):
7823
            ret = glusterd_snapshot_clone_commit(dict, op_errstr, rsp_dict);
7824
            if (ret) {
7825
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CLONE_FAILED,
7826
                       "Failed to "
7827
                       "clone snapshot");
7828
                goto out;
7829
            }
7830
            break;
7831

7832
        case GF_SNAP_OPTION_TYPE_CONFIG:
7833
            ret = glusterd_snapshot_config_commit(dict, op_errstr, rsp_dict);
7834
            if (ret) {
7835
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CONFIG_FAIL,
7836
                       "snapshot config failed");
7837
                goto out;
7838
            }
7839
            break;
7840

7841
        case GF_SNAP_OPTION_TYPE_DELETE:
7842
            ret = glusterd_snapshot_remove_commit(dict, op_errstr, rsp_dict);
7843
            if (ret) {
7844
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
7845
                       "Failed to "
7846
                       "delete snapshot");
7847
                if (*op_errstr) {
7848
                    /* If error string is already set
7849
                     * then goto out */
7850
                    goto out;
7851
                }
7852

7853
                ret = dict_get_str(dict, "snapname", &snap_name);
7854
                if (ret) {
7855
                    gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7856
                           "Failed to get snapname");
7857
                    snap_name = "NA";
7858
                }
7859

7860
                snprintf(temp, sizeof(temp),
7861
                         "Snapshot %s might "
7862
                         "not be in an usable state.",
7863
                         snap_name);
7864

7865
                *op_errstr = gf_strdup(temp);
7866
                ret = -1;
7867
                goto out;
7868
            }
7869
            break;
7870

7871
        case GF_SNAP_OPTION_TYPE_RESTORE:
7872
            ret = glusterd_snapshot_restore(dict, op_errstr, rsp_dict);
7873
            if (ret) {
7874
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
7875
                       "Failed to "
7876
                       "restore snapshot");
7877
                goto out;
7878
            }
7879

7880
            break;
7881
        case GF_SNAP_OPTION_TYPE_ACTIVATE:
7882
            ret = glusterd_snapshot_activate_commit(dict, op_errstr, rsp_dict);
7883
            if (ret) {
7884
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
7885
                       "Failed to "
7886
                       "activate snapshot");
7887
                goto out;
7888
            }
7889

7890
            break;
7891

7892
        case GF_SNAP_OPTION_TYPE_DEACTIVATE:
7893
            ret = glusterd_snapshot_deactivate_commit(dict, op_errstr,
7894
                                                      rsp_dict);
7895
            if (ret) {
7896
                gf_msg(this->name, GF_LOG_WARNING, 0,
7897
                       GD_MSG_SNAP_DEACTIVATE_FAIL,
7898
                       "Failed to "
7899
                       "deactivate snapshot");
7900
                goto out;
7901
            }
7902

7903
            break;
7904

7905
        case GF_SNAP_OPTION_TYPE_STATUS:
7906
            ret = glusterd_snapshot_status_commit(dict, op_errstr, rsp_dict);
7907
            if (ret) {
7908
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7909
                       "Failed to "
7910
                       "show snapshot status");
7911
                goto out;
7912
            }
7913
            break;
7914

7915
        default:
7916
            gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
7917
                   "invalid snap command");
7918
            goto out;
7919
            break;
7920
    }
7921

7922
    ret = 0;
7923

7924
out:
7925
    return ret;
7926
}
7927

7928
int
7929
glusterd_snapshot_brickop(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
7930
{
7931
    int ret = -1;
7932
    int64_t vol_count = 0;
7933
    int64_t count = 1;
7934
    char key[64] = "";
7935
    int keylen;
7936
    char *volname = NULL;
7937
    int32_t snap_command = 0;
7938
    xlator_t *this = THIS;
7939
    char *op_type = NULL;
7940

7941
    GF_ASSERT(dict);
7942
    GF_ASSERT(rsp_dict);
7943

7944
    ret = dict_get_int32(dict, "type", &snap_command);
7945
    if (ret) {
7946
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
7947
               "unable to get the type of "
7948
               "the snapshot command");
7949
        goto out;
7950
    }
7951

7952
    switch (snap_command) {
7953
        case GF_SNAP_OPTION_TYPE_CREATE:
7954

7955
            /* op_type with tell us whether its pre-commit operation
7956
             * or post-commit
7957
             */
7958
            ret = dict_get_str(dict, "operation-type", &op_type);
7959
            if (ret) {
7960
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7961
                       "Failed to fetch "
7962
                       "operation type");
7963
                goto out;
7964
            }
7965

7966
            if (strcmp(op_type, "pre") == 0) {
7967
                /* BRICK OP PHASE for enabling barrier, Enable barrier
7968
                 * if its a pre-commit operation
7969
                 */
7970
                ret = glusterd_set_barrier_value(dict, "enable");
7971
                if (ret) {
7972
                    gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7973
                           "Failed to "
7974
                           "set barrier value as enable in dict");
7975
                    goto out;
7976
                }
7977
            } else if (strcmp(op_type, "post") == 0) {
7978
                /* BRICK OP PHASE for disabling barrier, Disable barrier
7979
                 * if its a post-commit operation
7980
                 */
7981
                ret = glusterd_set_barrier_value(dict, "disable");
7982
                if (ret) {
7983
                    gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7984
                           "Failed to "
7985
                           "set barrier value as disable in "
7986
                           "dict");
7987
                    goto out;
7988
                }
7989
            } else {
7990
                ret = -1;
7991
                gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
7992
                       "Invalid op_type");
7993
                goto out;
7994
            }
7995

7996
            ret = dict_get_int64(dict, "volcount", &vol_count);
7997
            if (ret)
7998
                goto out;
7999
            while (count <= vol_count) {
8000
                keylen = snprintf(key, sizeof(key), "volname%" PRId64, count);
8001
                ret = dict_get_strn(dict, key, keylen, &volname);
8002
                if (ret) {
8003
                    gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8004
                           "Unable to get volname");
8005
                    goto out;
8006
                }
8007
                ret = dict_set_str_sizen(dict, "volname", volname);
8008
                if (ret)
8009
                    goto out;
8010

8011
                ret = gd_brick_op_phase(GD_OP_SNAP, NULL, dict, op_errstr);
8012
                if (ret)
8013
                    goto out;
8014
                volname = NULL;
8015
                count++;
8016
            }
8017

8018
            dict_del_sizen(dict, "volname");
8019
            ret = 0;
8020
            break;
8021
        case GF_SNAP_OPTION_TYPE_DELETE:
8022
            break;
8023
        default:
8024
            break;
8025
    }
8026

8027
out:
8028
    return ret;
8029
}
8030

8031
int
8032
glusterd_snapshot_prevalidate(dict_t *dict, char **op_errstr, dict_t *rsp_dict,
8033
                              uint32_t *op_errno)
8034
{
8035
    int snap_command = 0;
8036
    xlator_t *this = THIS;
8037
    int ret = -1;
8038

8039
    GF_ASSERT(dict);
8040
    GF_ASSERT(rsp_dict);
8041
    GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
8042

8043
    ret = dict_get_int32(dict, "type", &snap_command);
8044
    if (ret) {
8045
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
8046
               "unable to get the type of "
8047
               "the snapshot command");
8048
        goto out;
8049
    }
8050

8051
    switch (snap_command) {
8052
        case (GF_SNAP_OPTION_TYPE_CREATE):
8053
            ret = glusterd_snapshot_create_prevalidate(dict, op_errstr,
8054
                                                       rsp_dict, op_errno);
8055
            if (ret) {
8056
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
8057
                       "Snapshot create "
8058
                       "pre-validation failed");
8059
                goto out;
8060
            }
8061
            break;
8062

8063
        case (GF_SNAP_OPTION_TYPE_CLONE):
8064
            ret = glusterd_snapshot_clone_prevalidate(dict, op_errstr, rsp_dict,
8065
                                                      op_errno);
8066
            if (ret) {
8067
                gf_msg(this->name, GF_LOG_WARNING, 0,
8068
                       GD_MSG_SNAP_CLONE_PREVAL_FAILED,
8069
                       "Snapshot clone "
8070
                       "pre-validation failed");
8071
                goto out;
8072
            }
8073
            break;
8074

8075
        case (GF_SNAP_OPTION_TYPE_CONFIG):
8076
            ret = glusterd_snapshot_config_prevalidate(dict, op_errstr,
8077
                                                       op_errno);
8078
            if (ret) {
8079
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CONFIG_FAIL,
8080
                       "Snapshot config "
8081
                       "pre-validation failed");
8082
                goto out;
8083
            }
8084
            break;
8085

8086
        case GF_SNAP_OPTION_TYPE_RESTORE:
8087
            ret = glusterd_snapshot_restore_prevalidate(dict, op_errstr,
8088
                                                        op_errno, rsp_dict);
8089
            if (ret) {
8090
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
8091
                       "Snapshot restore "
8092
                       "validation failed");
8093
                goto out;
8094
            }
8095
            break;
8096

8097
        case GF_SNAP_OPTION_TYPE_ACTIVATE:
8098
            ret = glusterd_snapshot_activate_deactivate_prevalidate(
8099
                dict, op_errstr, op_errno, rsp_dict, _gf_true);
8100
            if (ret) {
8101
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
8102
                       "Snapshot activate "
8103
                       "validation failed");
8104
                goto out;
8105
            }
8106
            break;
8107
        case GF_SNAP_OPTION_TYPE_DEACTIVATE:
8108
            ret = glusterd_snapshot_activate_deactivate_prevalidate(
8109
                dict, op_errstr, op_errno, rsp_dict, _gf_false);
8110
            if (ret) {
8111
                gf_msg(this->name, GF_LOG_WARNING, 0,
8112
                       GD_MSG_SNAP_DEACTIVATE_FAIL,
8113
                       "Snapshot deactivate validation failed");
8114
                goto out;
8115
            }
8116
            break;
8117
        case GF_SNAP_OPTION_TYPE_DELETE:
8118
            ret = glusterd_snapshot_remove_prevalidate(dict, op_errstr,
8119
                                                       op_errno, rsp_dict);
8120
            if (ret) {
8121
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
8122
                       "Snapshot remove "
8123
                       "validation failed");
8124
                goto out;
8125
            }
8126
            break;
8127

8128
        case GF_SNAP_OPTION_TYPE_STATUS:
8129
            ret = glusterd_snapshot_status_prevalidate(dict, op_errstr,
8130
                                                       op_errno, rsp_dict);
8131
            if (ret) {
8132
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_STATUS_FAIL,
8133
                       "Snapshot status "
8134
                       "validation failed");
8135
                goto out;
8136
            }
8137
            break;
8138

8139
        default:
8140
            gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
8141
                   "invalid snap command");
8142
            *op_errno = EINVAL;
8143
            goto out;
8144
    }
8145

8146
    ret = 0;
8147
out:
8148
    return ret;
8149
}
8150

8151
/* This function is called to remove the trashpath, in cases
8152
 * when the restore operation is successful and we don't need
8153
 * the backup, and incases when the restore op is failed before
8154
 * commit, and we don't need to revert the backup.
8155
 *
8156
 * @param volname  name of the volume which is being restored
8157
 *
8158
 * @return 0 on success or -1 on failure
8159
 */
8160
int
8161
glusterd_remove_trashpath(char *volname)
8162
{
8163
    int ret = -1;
8164
    char delete_path[PATH_MAX] = {
8165
        0,
8166
    };
8167
    xlator_t *this = THIS;
8168
    glusterd_conf_t *priv = NULL;
8169
    struct stat stbuf = {
8170
        0,
8171
    };
8172
    int32_t len = 0;
8173

8174
    priv = this->private;
8175

8176
    GF_ASSERT(volname);
8177

8178
    len = snprintf(delete_path, sizeof(delete_path),
8179
                   "%s/" GLUSTERD_TRASH "/vols-%s.deleted", priv->workdir,
8180
                   volname);
8181
    if ((len < 0) || (len >= sizeof(delete_path))) {
8182
        goto out;
8183
    }
8184

8185
    ret = sys_lstat(delete_path, &stbuf);
8186
    if (ret) {
8187
        /* If the trash dir does not exist, return *
8188
         * without failure                         *
8189
         */
8190
        if (errno == ENOENT) {
8191
            ret = 0;
8192
            goto out;
8193
        } else {
8194
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8195
                   "Failed to lstat "
8196
                   "backup dir (%s)",
8197
                   delete_path);
8198
            goto out;
8199
        }
8200
    }
8201

8202
    /* Delete the backup copy of volume folder */
8203
    ret = recursive_rmdir(delete_path);
8204
    if (ret) {
8205
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8206
               "Failed to remove "
8207
               "backup dir (%s)",
8208
               delete_path);
8209
        goto out;
8210
    }
8211

8212
    ret = 0;
8213
out:
8214
    return ret;
8215
}
8216

8217
/* This function is called if snapshot restore operation
8218
 * is successful. It will cleanup the backup files created
8219
 * during the restore operation.
8220
 *
8221
 * @param rsp_dict Response dictionary
8222
 * @param volinfo  volinfo of the volume which is being restored
8223
 * @param snap     snap object
8224
 *
8225
 * @return 0 on success or -1 on failure
8226
 */
8227
int
8228
glusterd_snapshot_restore_cleanup(dict_t *rsp_dict, char *volname,
8229
                                  glusterd_snap_t *snap)
8230
{
8231
    int ret = -1;
8232

8233
    GF_ASSERT(rsp_dict);
8234
    GF_ASSERT(volname);
8235
    GF_ASSERT(snap);
8236

8237
    /* Now delete the snap entry. */
8238
    ret = glusterd_snap_remove(rsp_dict, snap, _gf_false, _gf_true, _gf_false);
8239
    if (ret) {
8240
        gf_msg(THIS->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
8241
               "Failed to delete "
8242
               "snap %s",
8243
               snap->snapname);
8244
        goto out;
8245
    }
8246

8247
    /* Delete the backup copy of volume folder */
8248
    ret = glusterd_remove_trashpath(volname);
8249
    if (ret) {
8250
        gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8251
               "Failed to remove "
8252
               "backup dir");
8253
        goto out;
8254
    }
8255

8256
    ret = 0;
8257
out:
8258
    return ret;
8259
}
8260

8261
/* This function is called when the snapshot restore operation failed
8262
 * for some reasons. In such case we revert the restore operation.
8263
 *
8264
 * @param volinfo               volinfo of the origin volume
8265
 *
8266
 * @return 0 on success and -1 on failure
8267
 */
8268
int
8269
glusterd_snapshot_revert_partial_restored_vol(glusterd_volinfo_t *volinfo)
8270
{
8271
    int ret = 0;
8272
    char pathname[PATH_MAX] = "";
8273
    char trash_path[PATH_MAX] = "";
8274
    glusterd_brickinfo_t *brickinfo = NULL;
8275
    glusterd_volinfo_t *reverted_vol = NULL;
8276
    glusterd_volinfo_t *snap_vol = NULL;
8277
    glusterd_volinfo_t *tmp_vol = NULL;
8278
    glusterd_conf_t *priv = NULL;
8279
    xlator_t *this = THIS;
8280
    int32_t len = 0;
8281

8282
    priv = this->private;
8283
    GF_ASSERT(priv);
8284
    GF_ASSERT(volinfo);
8285

8286
    GLUSTERD_GET_VOLUME_DIR(pathname, volinfo, priv);
8287

8288
    len = snprintf(trash_path, sizeof(trash_path),
8289
                   "%s/" GLUSTERD_TRASH "/vols-%s.deleted", priv->workdir,
8290
                   volinfo->volname);
8291
    if ((len < 0) || (len >= sizeof(trash_path))) {
8292
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
8293
        ret = -1;
8294
        goto out;
8295
    }
8296

8297
    /* Since snapshot restore failed we cannot rely on the volume
8298
     * data stored under vols folder. Therefore delete the origin
8299
     * volume's backend folder.*/
8300
    ret = recursive_rmdir(pathname);
8301
    if (ret) {
8302
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8303
               "Failed to remove "
8304
               "%s directory",
8305
               pathname);
8306
        goto out;
8307
    }
8308

8309
    /* Now move the backup copy of the vols to its original
8310
     * location.*/
8311
    ret = sys_rename(trash_path, pathname);
8312
    if (ret) {
8313
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8314
               "Failed to rename folder "
8315
               "from %s to %s",
8316
               trash_path, pathname);
8317
        goto out;
8318
    }
8319

8320
    /* Retrieve the volume from the store */
8321
    reverted_vol = glusterd_store_retrieve_volume(volinfo->volname, NULL);
8322
    if (NULL == reverted_vol) {
8323
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
8324
               "Failed to load restored "
8325
               "%s volume",
8326
               volinfo->volname);
8327
        goto out;
8328
    }
8329

8330
    /* Retrieve the snap_volumes list from the older volinfo */
8331
    reverted_vol->snap_count = volinfo->snap_count;
8332
    cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
8333
                                 snapvol_list)
8334
    {
8335
        cds_list_add_tail(&snap_vol->snapvol_list, &reverted_vol->snap_volumes);
8336

8337
        cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
8338
        {
8339
            /*
8340
             * If the brick is not of this peer, or snapshot is    *
8341
             * missed for the brick don't restore the xattr for it *
8342
             */
8343
            if ((!gf_uuid_compare(brickinfo->uuid, MY_UUID)) &&
8344
                (brickinfo->snap_status != -1)) {
8345
                /*
8346
                 * We need to restore volume id of all snap *
8347
                 * bricks to volume id of the snap volume.  *
8348
                 */
8349
                ret = sys_lsetxattr(brickinfo->path, GF_XATTR_VOL_ID_KEY,
8350
                                    snap_vol->volume_id,
8351
                                    sizeof(snap_vol->volume_id), XATTR_REPLACE);
8352
                if (ret == -1) {
8353
                    gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_SET_XATTR_FAIL,
8354
                            "Attribute=%s, Path=%s, Reason=%s, Snap=%s",
8355
                            GF_XATTR_VOL_ID_KEY, brickinfo->path,
8356
                            strerror(errno), snap_vol->volname, NULL);
8357
                    goto out;
8358
                }
8359
            }
8360
        }
8361
    }
8362

8363
    ret = 0;
8364
out:
8365
    return ret;
8366
}
8367

8368
/* This function is called when glusterd is started and we need
8369
 * to revert a failed snapshot restore.
8370
 *
8371
 * @param snap snapshot object of the restored snap
8372
 *
8373
 * @return 0 on success and -1 on failure
8374
 */
8375
int
8376
glusterd_snapshot_revert_restore_from_snap(glusterd_snap_t *snap)
8377
{
8378
    int ret = -1;
8379
    char volname[PATH_MAX] = "";
8380
    glusterd_volinfo_t *snap_volinfo = NULL;
8381
    glusterd_volinfo_t *volinfo = NULL;
8382
    GF_ASSERT(snap);
8383

8384
    /* TODO : As of now there is only one volume in snapshot.
8385
     * Change this when multiple volume snapshot is introduced
8386
     */
8387
    snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
8388
                                  vol_list);
8389

8390
    gf_strncpy(volname, snap_volinfo->parent_volname, sizeof(volname));
8391

8392
    ret = glusterd_volinfo_find(volname, &volinfo);
8393
    if (ret) {
8394
        gf_msg(THIS->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
8395
               "Could not get volinfo of "
8396
               "%s",
8397
               snap_volinfo->parent_volname);
8398
        goto out;
8399
    }
8400

8401
    ret = glusterd_snapshot_revert_partial_restored_vol(volinfo);
8402
    if (ret) {
8403
        gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_REVERT_FAIL,
8404
               "Failed to revert snapshot "
8405
               "restore operation for %s volume",
8406
               volname);
8407
        goto out;
8408
    }
8409

8410
    /* The above function retrieves the volinfo from store now we don't
8411
     * want the older volinfo. Therefore delete the older volinfo */
8412
    glusterd_volinfo_unref(volinfo);
8413

8414
out:
8415
    return ret;
8416
}
8417

8418
/* This function is called from post-validation. Based on the op_ret
8419
 * it will take a decision on whether to revert the operation or
8420
 * perform cleanup.
8421
 *
8422
 * @param dict          dictionary object
8423
 * @param op_ret        return value of the restore operation
8424
 * @param op_errstr     error string
8425
 * @param rsp_dict      Response dictionary
8426
 *
8427
 * @return 0 on success and -1 on failure
8428
 */
8429
int
8430
glusterd_snapshot_restore_postop(dict_t *dict, int32_t op_ret, char **op_errstr,
8431
                                 dict_t *rsp_dict)
8432
{
8433
    int ret = -1;
8434
    char *name = NULL;
8435
    char *volname = NULL;
8436
    int cleanup = 0;
8437
    glusterd_snap_t *snap = NULL;
8438
    glusterd_volinfo_t *volinfo = NULL;
8439
    xlator_t *this = THIS;
8440

8441
    GF_ASSERT(dict);
8442
    GF_ASSERT(rsp_dict);
8443

8444
    ret = dict_get_str(dict, "snapname", &name);
8445
    if (ret) {
8446
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8447
               "getting the snap "
8448
               "name failed (volume: %s)",
8449
               name);
8450
        goto out;
8451
    }
8452

8453
    snap = glusterd_find_snap_by_name(name);
8454
    if (!snap) {
8455
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
8456
               "Snapshot (%s) does not exist", name);
8457
        ret = -1;
8458
        goto out;
8459
    }
8460

8461
    /* TODO: fix this when multiple volume support will come */
8462
    ret = dict_get_str(dict, "volname1", &volname);
8463
    if (ret) {
8464
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8465
               "failed to get volume name");
8466
        goto out;
8467
    }
8468

8469
    ret = glusterd_volinfo_find(volname, &volinfo);
8470
    if (ret) {
8471
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
8472
               "Volume (%s) does not exist ", volname);
8473
        goto out;
8474
    }
8475

8476
    ret = dict_get_str(dict, "snapname", &name);
8477
    if (ret) {
8478
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8479
               "getting the snap "
8480
               "name failed (volume: %s)",
8481
               volinfo->volname);
8482
        goto out;
8483
    }
8484

8485
    snap = glusterd_find_snap_by_name(name);
8486
    if (!snap) {
8487
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
8488
               "snap %s is not found", name);
8489
        ret = -1;
8490
        goto out;
8491
    }
8492

8493
    /* On success perform the cleanup operation */
8494
    if (0 == op_ret) {
8495
        ret = glusterd_snapshot_restore_cleanup(rsp_dict, volname, snap);
8496
        if (ret) {
8497
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CLEANUP_FAIL,
8498
                   "Failed to perform "
8499
                   "snapshot restore cleanup for %s volume",
8500
                   volname);
8501
            goto out;
8502
        }
8503
    } else { /* On failure revert snapshot restore */
8504
        ret = dict_get_int32(dict, "cleanup", &cleanup);
8505
        /* Perform cleanup only when required */
8506
        if (ret || (0 == cleanup)) {
8507
            /* Delete the backup copy of volume folder */
8508
            ret = glusterd_remove_trashpath(volinfo->volname);
8509
            if (ret) {
8510
                gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8511
                       "Failed to remove backup dir");
8512
                goto out;
8513
            }
8514
            ret = 0;
8515
            goto out;
8516
        }
8517

8518
        ret = glusterd_snapshot_revert_partial_restored_vol(volinfo);
8519
        if (ret) {
8520
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_REVERT_FAIL,
8521
                   "Failed to revert "
8522
                   "restore operation for %s volume",
8523
                   volname);
8524
            goto out;
8525
        }
8526

8527
        snap->snap_status = GD_SNAP_STATUS_IN_USE;
8528
        /* We need to save this in disk */
8529
        ret = glusterd_store_snap(snap);
8530
        if (ret) {
8531
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJECT_STORE_FAIL,
8532
                   "Could not store snap object for %s snap", snap->snapname);
8533
            goto out;
8534
        }
8535

8536
        /* After restore fails, we have to remove mount point for
8537
         * deactivated snaps which was created at start of restore op.
8538
         */
8539

8540
        if (volinfo->status == GLUSTERD_STATUS_STOPPED) {
8541
            ret = glusterd_snap_unmount(this, volinfo);
8542
            if (ret) {
8543
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_UMOUNT_FAIL,
8544
                       "Failed to unmounts for %s", snap->snapname);
8545
            }
8546
        }
8547

8548
        /* The function glusterd_snapshot_revert_partial_restored_vol()
8549
         * retrieves the volinfo from store now we don't want the older
8550
         * volinfo. Therefore delete the older volinfo */
8551
        glusterd_volinfo_unref(volinfo);
8552
    }
8553

8554
    ret = 0;
8555
out:
8556
    return ret;
8557
}
8558

8559
int
8560
glusterd_snapshot_postvalidate(dict_t *dict, int32_t op_ret, char **op_errstr,
8561
                               dict_t *rsp_dict)
8562
{
8563
    int snap_command = 0;
8564
    xlator_t *this = THIS;
8565
    int ret = -1;
8566

8567
    GF_ASSERT(dict);
8568
    GF_ASSERT(rsp_dict);
8569

8570
    ret = dict_get_int32(dict, "type", &snap_command);
8571
    if (ret) {
8572
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
8573
               "unable to get the type of "
8574
               "the snapshot command");
8575
        goto out;
8576
    }
8577

8578
    switch (snap_command) {
8579
        case GF_SNAP_OPTION_TYPE_CREATE:
8580
            ret = glusterd_snapshot_create_postvalidate(dict, op_ret, op_errstr,
8581
                                                        rsp_dict);
8582
            if (ret) {
8583
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
8584
                       "Snapshot create "
8585
                       "post-validation failed");
8586
                goto out;
8587
            }
8588
            glusterd_fetchsnap_notify(this);
8589
            break;
8590
        case GF_SNAP_OPTION_TYPE_CLONE:
8591
            ret = glusterd_snapshot_clone_postvalidate(dict, op_ret, op_errstr,
8592
                                                       rsp_dict);
8593
            if (ret) {
8594
                gf_msg(this->name, GF_LOG_WARNING, 0,
8595
                       GD_MSG_SNAP_CLONE_POSTVAL_FAILED,
8596
                       "Snapshot create "
8597
                       "post-validation failed");
8598
                goto out;
8599
            }
8600
            glusterd_fetchsnap_notify(this);
8601
            break;
8602
        case GF_SNAP_OPTION_TYPE_DELETE:
8603
            if (op_ret) {
8604
                gf_msg_debug(this->name, 0,
8605
                             "op_ret = %d. Not performing delete "
8606
                             "post_validate",
8607
                             op_ret);
8608
                ret = 0;
8609
                goto out;
8610
            }
8611
            ret = glusterd_snapshot_update_snaps_post_validate(dict, op_errstr,
8612
                                                               rsp_dict);
8613
            if (ret) {
8614
                gf_msg(this->name, GF_LOG_ERROR, 0,
8615
                       GD_MSG_MISSED_SNAP_LIST_STORE_FAIL,
8616
                       "Failed to "
8617
                       "update missed snaps list");
8618
                goto out;
8619
            }
8620
            glusterd_fetchsnap_notify(this);
8621
            break;
8622
        case GF_SNAP_OPTION_TYPE_RESTORE:
8623
            ret = glusterd_snapshot_update_snaps_post_validate(dict, op_errstr,
8624
                                                               rsp_dict);
8625
            if (ret) {
8626
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
8627
                       "Failed to "
8628
                       "update missed snaps list");
8629
                goto out;
8630
            }
8631

8632
            ret = glusterd_snapshot_restore_postop(dict, op_ret, op_errstr,
8633
                                                   rsp_dict);
8634
            if (ret) {
8635
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
8636
                       "Failed to "
8637
                       "perform snapshot restore post-op");
8638
                goto out;
8639
            }
8640
            glusterd_fetchsnap_notify(this);
8641
            break;
8642
        case GF_SNAP_OPTION_TYPE_ACTIVATE:
8643
        case GF_SNAP_OPTION_TYPE_DEACTIVATE:
8644
            glusterd_fetchsnap_notify(this);
8645
            break;
8646
        case GF_SNAP_OPTION_TYPE_STATUS:
8647
        case GF_SNAP_OPTION_TYPE_CONFIG:
8648
        case GF_SNAP_OPTION_TYPE_INFO:
8649
        case GF_SNAP_OPTION_TYPE_LIST:
8650
            /*Nothing to be done. But want to
8651
             * avoid the default case warning*/
8652
            ret = 0;
8653
            break;
8654
        default:
8655
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_COMMAND_NOT_FOUND,
8656
                   "invalid snap command");
8657
            goto out;
8658
    }
8659

8660
    ret = 0;
8661
out:
8662
    return ret;
8663
}
8664

8665
int
8666
glusterd_handle_snapshot_fn(rpcsvc_request_t *req)
8667
{
8668
    int32_t ret = 0;
8669
    dict_t *dict = NULL;
8670
    gf_cli_req cli_req = {
8671
        {0},
8672
    };
8673
    glusterd_op_t cli_op = GD_OP_SNAP;
8674
    int type = 0;
8675
    char *host_uuid = NULL;
8676
    char err_str[2048] = "";
8677
    xlator_t *this = THIS;
8678
    uint32_t op_errno = 0;
8679

8680
    GF_ASSERT(req);
8681

8682
    ret = xdr_to_generic(req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);
8683
    if (ret < 0) {
8684
        req->rpc_err = GARBAGE_ARGS;
8685
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_GARBAGE_ARGS, NULL);
8686
        goto out;
8687
    }
8688

8689
    if (cli_req.dict.dict_len > 0) {
8690
        dict = dict_new();
8691
        if (!dict)
8692
            goto out;
8693

8694
        ret = dict_unserialize(cli_req.dict.dict_val, cli_req.dict.dict_len,
8695
                               &dict);
8696
        if (ret < 0) {
8697
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_UNSERIALIZE_FAIL,
8698
                   "failed to "
8699
                   "unserialize req-buffer to dictionary");
8700
            snprintf(err_str, sizeof(err_str),
8701
                     "Unable to decode "
8702
                     "the command");
8703
            goto out;
8704
        }
8705

8706
        dict->extra_stdfree = cli_req.dict.dict_val;
8707

8708
        host_uuid = gf_strdup(uuid_utoa(MY_UUID));
8709
        if (host_uuid == NULL) {
8710
            snprintf(err_str, sizeof(err_str),
8711
                     "Failed to get "
8712
                     "the uuid of local glusterd");
8713
            ret = -1;
8714
            goto out;
8715
        }
8716
        ret = dict_set_dynstr_sizen(dict, "host-uuid", host_uuid);
8717
        if (ret) {
8718
            GF_FREE(host_uuid);
8719
            goto out;
8720
        }
8721

8722
    } else {
8723
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
8724
               "request dict length is %d", cli_req.dict.dict_len);
8725
        goto out;
8726
    }
8727

8728
    ret = dict_get_int32(dict, "type", &type);
8729

8730
    if (ret < 0) {
8731
        snprintf(err_str, sizeof(err_str), "Command type not found");
8732
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND, "%s",
8733
               err_str);
8734
        goto out;
8735
    }
8736

8737
    switch (type) {
8738
        case GF_SNAP_OPTION_TYPE_CREATE:
8739
            ret = glusterd_handle_snapshot_create(req, cli_op, dict, err_str,
8740
                                                  sizeof(err_str));
8741
            if (ret) {
8742
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
8743
                       "Snapshot create failed: %s", err_str);
8744
            }
8745
            break;
8746

8747
        case GF_SNAP_OPTION_TYPE_CLONE:
8748
            ret = glusterd_handle_snapshot_clone(req, cli_op, dict, err_str,
8749
                                                 sizeof(err_str));
8750
            if (ret) {
8751
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CLONE_FAILED,
8752
                       "Snapshot clone "
8753
                       "failed: %s",
8754
                       err_str);
8755
            }
8756
            break;
8757

8758
        case GF_SNAP_OPTION_TYPE_RESTORE:
8759
            ret = glusterd_handle_snapshot_restore(req, cli_op, dict, err_str,
8760
                                                   &op_errno, sizeof(err_str));
8761
            if (ret) {
8762
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
8763
                       "Snapshot restore failed: %s", err_str);
8764
            }
8765

8766
            break;
8767
        case GF_SNAP_OPTION_TYPE_INFO:
8768
            ret = glusterd_handle_snapshot_info(req, cli_op, dict, err_str,
8769
                                                sizeof(err_str));
8770
            if (ret) {
8771
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_INFO_FAIL,
8772
                       "Snapshot info failed");
8773
            }
8774
            break;
8775
        case GF_SNAP_OPTION_TYPE_LIST:
8776
            ret = glusterd_handle_snapshot_list(req, cli_op, dict, err_str,
8777
                                                sizeof(err_str), &op_errno);
8778
            if (ret) {
8779
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_LIST_GET_FAIL,
8780
                       "Snapshot list failed");
8781
            }
8782
            break;
8783
        case GF_SNAP_OPTION_TYPE_CONFIG:
8784
            ret = glusterd_handle_snapshot_config(req, cli_op, dict, err_str,
8785
                                                  sizeof(err_str));
8786
            if (ret) {
8787
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CONFIG_FAIL,
8788
                       "snapshot config failed");
8789
            }
8790
            break;
8791
        case GF_SNAP_OPTION_TYPE_DELETE:
8792
            ret = glusterd_handle_snapshot_delete(req, cli_op, dict, err_str,
8793
                                                  &op_errno, sizeof(err_str));
8794
            if (ret) {
8795
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
8796
                       "Snapshot delete failed: %s", err_str);
8797
            }
8798
            break;
8799
        case GF_SNAP_OPTION_TYPE_ACTIVATE:
8800
            ret = glusterd_mgmt_v3_initiate_snap_phases(req, cli_op, dict);
8801
            if (ret) {
8802
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
8803
                       "Snapshot activate failed: %s", err_str);
8804
            }
8805
            break;
8806
        case GF_SNAP_OPTION_TYPE_DEACTIVATE:
8807
            ret = glusterd_mgmt_v3_initiate_snap_phases(req, cli_op, dict);
8808
            if (ret) {
8809
                gf_msg(this->name, GF_LOG_WARNING, 0,
8810
                       GD_MSG_SNAP_DEACTIVATE_FAIL,
8811
                       "Snapshot deactivate failed: %s", err_str);
8812
            }
8813
            break;
8814
        case GF_SNAP_OPTION_TYPE_STATUS:
8815
            ret = glusterd_handle_snapshot_status(req, cli_op, dict, err_str,
8816
                                                  sizeof(err_str));
8817
            if (ret) {
8818
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_STATUS_FAIL,
8819
                       "Snapshot status failed: %s", err_str);
8820
            }
8821
            break;
8822
        default:
8823
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
8824
                   "Unknown snapshot request "
8825
                   "type (%d)",
8826
                   type);
8827
            ret = -1; /* Failure */
8828
    }
8829

8830
out:
8831
    if (ret) {
8832
        if (err_str[0] == '\0')
8833
            snprintf(err_str, sizeof(err_str), "Operation failed");
8834

8835
        if (ret && (op_errno == 0))
8836
            op_errno = EG_INTRNL;
8837

8838
        ret = glusterd_op_send_cli_response(cli_op, ret, op_errno, req, dict,
8839
                                            err_str);
8840
    }
8841

8842
    return ret;
8843
}
8844

8845
int
8846
glusterd_handle_snapshot(rpcsvc_request_t *req)
8847
{
8848
    return glusterd_big_locked_handler(req, glusterd_handle_snapshot_fn);
8849
}
8850

8851
static void
8852
glusterd_free_snap_op(glusterd_snap_op_t *snap_op)
8853
{
8854
    if (snap_op) {
8855
        if (snap_op->brick_path)
8856
            GF_FREE(snap_op->brick_path);
8857

8858
        GF_FREE(snap_op);
8859
    }
8860
}
8861

8862
static void
8863
glusterd_free_missed_snapinfo(glusterd_missed_snap_info *missed_snapinfo)
8864
{
8865
    glusterd_snap_op_t *snap_opinfo = NULL;
8866
    glusterd_snap_op_t *tmp = NULL;
8867

8868
    if (missed_snapinfo) {
8869
        cds_list_for_each_entry_safe(snap_opinfo, tmp,
8870
                                     &missed_snapinfo->snap_ops, snap_ops_list)
8871
        {
8872
            glusterd_free_snap_op(snap_opinfo);
8873
            snap_opinfo = NULL;
8874
        }
8875

8876
        if (missed_snapinfo->node_uuid)
8877
            GF_FREE(missed_snapinfo->node_uuid);
8878

8879
        if (missed_snapinfo->snap_uuid)
8880
            GF_FREE(missed_snapinfo->snap_uuid);
8881

8882
        GF_FREE(missed_snapinfo);
8883
    }
8884
}
8885

8886
/* Look for duplicates and accordingly update the list */
8887
int32_t
8888
glusterd_update_missed_snap_entry(glusterd_missed_snap_info *missed_snapinfo,
8889
                                  glusterd_snap_op_t *missed_snap_op)
8890
{
8891
    int32_t ret = -1;
8892
    glusterd_snap_op_t *snap_opinfo = NULL;
8893
    gf_boolean_t match = _gf_false;
8894
    xlator_t *this = THIS;
8895

8896
    GF_ASSERT(missed_snapinfo);
8897
    GF_ASSERT(missed_snap_op);
8898

8899
    cds_list_for_each_entry(snap_opinfo, &missed_snapinfo->snap_ops,
8900
                            snap_ops_list)
8901
    {
8902
        /* If the entry is not for the same snap_vol_id
8903
         * then continue
8904
         */
8905
        if (strcmp(snap_opinfo->snap_vol_id, missed_snap_op->snap_vol_id))
8906
            continue;
8907

8908
        if ((!strcmp(snap_opinfo->brick_path, missed_snap_op->brick_path)) &&
8909
            (snap_opinfo->op == missed_snap_op->op)) {
8910
            /* If two entries have conflicting status
8911
             * GD_MISSED_SNAP_DONE takes precedence
8912
             */
8913
            if ((snap_opinfo->status == GD_MISSED_SNAP_PENDING) &&
8914
                (missed_snap_op->status == GD_MISSED_SNAP_DONE)) {
8915
                snap_opinfo->status = GD_MISSED_SNAP_DONE;
8916
                gf_msg(this->name, GF_LOG_INFO, 0,
8917
                       GD_MSG_MISSED_SNAP_STATUS_DONE,
8918
                       "Updating missed snap status "
8919
                       "for %s:%s=%s:%d:%s:%d as DONE",
8920
                       missed_snapinfo->node_uuid, missed_snapinfo->snap_uuid,
8921
                       snap_opinfo->snap_vol_id, snap_opinfo->brick_num,
8922
                       snap_opinfo->brick_path, snap_opinfo->op);
8923
                ret = 0;
8924
                glusterd_free_snap_op(missed_snap_op);
8925
                goto out;
8926
            }
8927
            match = _gf_true;
8928
            break;
8929
        } else if ((snap_opinfo->brick_num == missed_snap_op->brick_num) &&
8930
                   (snap_opinfo->op == GF_SNAP_OPTION_TYPE_CREATE) &&
8931
                   ((missed_snap_op->op == GF_SNAP_OPTION_TYPE_DELETE) ||
8932
                    (missed_snap_op->op == GF_SNAP_OPTION_TYPE_RESTORE))) {
8933
            /* Optimizing create and delete entries for the same
8934
             * brick and same node
8935
             */
8936
            gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_MISSED_SNAP_STATUS_DONE,
8937
                   "Updating missed snap status "
8938
                   "for %s:%s=%s:%d:%s:%d as DONE",
8939
                   missed_snapinfo->node_uuid, missed_snapinfo->snap_uuid,
8940
                   snap_opinfo->snap_vol_id, snap_opinfo->brick_num,
8941
                   snap_opinfo->brick_path, snap_opinfo->op);
8942
            snap_opinfo->status = GD_MISSED_SNAP_DONE;
8943
            ret = 0;
8944
            glusterd_free_snap_op(missed_snap_op);
8945
            goto out;
8946
        }
8947
    }
8948

8949
    if (match == _gf_true) {
8950
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DUP_ENTRY,
8951
               "Duplicate entry. Not updating");
8952
        glusterd_free_snap_op(missed_snap_op);
8953
    } else {
8954
        cds_list_add_tail(&missed_snap_op->snap_ops_list,
8955
                          &missed_snapinfo->snap_ops);
8956
    }
8957

8958
    ret = 0;
8959
out:
8960
    gf_msg_trace(this->name, 0, "Returning %d", ret);
8961
    return ret;
8962
}
8963

8964
/* Add new missed snap entry to the missed_snaps list. */
8965
int32_t
8966
glusterd_add_new_entry_to_list(char *missed_info, char *snap_vol_id,
8967
                               int32_t brick_num, char *brick_path,
8968
                               int32_t snap_op, int32_t snap_status)
8969
{
8970
    char *buf = NULL;
8971
    char *save_ptr = NULL;
8972
    char node_snap_info[PATH_MAX] = "";
8973
    int32_t ret = -1;
8974
    glusterd_missed_snap_info *missed_snapinfo = NULL;
8975
    glusterd_snap_op_t *missed_snap_op = NULL;
8976
    glusterd_conf_t *priv = NULL;
8977
    gf_boolean_t match = _gf_false;
8978
    gf_boolean_t free_missed_snap_info = _gf_false;
8979
    xlator_t *this = THIS;
8980

8981
    GF_ASSERT(missed_info);
8982
    GF_ASSERT(snap_vol_id);
8983
    GF_ASSERT(brick_path);
8984

8985
    priv = this->private;
8986
    GF_ASSERT(priv);
8987

8988
    /* Create the snap_op object consisting of the *
8989
     * snap id and the op */
8990
    ret = glusterd_missed_snap_op_new(&missed_snap_op);
8991
    if (ret) {
8992
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL,
8993
               "Failed to create new missed snap object.");
8994
        ret = -1;
8995
        goto out;
8996
    }
8997

8998
    missed_snap_op->snap_vol_id = gf_strdup(snap_vol_id);
8999
    if (!missed_snap_op->snap_vol_id) {
9000
        ret = -1;
9001
        goto out;
9002
    }
9003
    missed_snap_op->brick_path = gf_strdup(brick_path);
9004
    if (!missed_snap_op->brick_path) {
9005
        ret = -1;
9006
        goto out;
9007
    }
9008
    missed_snap_op->brick_num = brick_num;
9009
    missed_snap_op->op = snap_op;
9010
    missed_snap_op->status = snap_status;
9011

9012
    /* Look for other entries for the same node and same snap */
9013
    cds_list_for_each_entry(missed_snapinfo, &priv->missed_snaps_list,
9014
                            missed_snaps)
9015
    {
9016
        snprintf(node_snap_info, sizeof(node_snap_info), "%s:%s",
9017
                 missed_snapinfo->node_uuid, missed_snapinfo->snap_uuid);
9018
        if (!strcmp(node_snap_info, missed_info)) {
9019
            /* Found missed snapshot info for *
9020
             * the same node and same snap */
9021
            match = _gf_true;
9022
            break;
9023
        }
9024
    }
9025

9026
    if (match == _gf_false) {
9027
        /* First snap op missed for the brick */
9028
        ret = glusterd_missed_snapinfo_new(&missed_snapinfo);
9029
        if (ret) {
9030
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL,
9031
                   "Failed to create missed snapinfo");
9032
            goto out;
9033
        }
9034
        free_missed_snap_info = _gf_true;
9035
        buf = strtok_r(missed_info, ":", &save_ptr);
9036
        if (!buf) {
9037
            ret = -1;
9038
            goto out;
9039
        }
9040
        missed_snapinfo->node_uuid = gf_strdup(buf);
9041
        if (!missed_snapinfo->node_uuid) {
9042
            ret = -1;
9043
            goto out;
9044
        }
9045

9046
        buf = strtok_r(NULL, ":", &save_ptr);
9047
        if (!buf) {
9048
            ret = -1;
9049
            goto out;
9050
        }
9051
        missed_snapinfo->snap_uuid = gf_strdup(buf);
9052
        if (!missed_snapinfo->snap_uuid) {
9053
            ret = -1;
9054
            goto out;
9055
        }
9056

9057
        cds_list_add_tail(&missed_snap_op->snap_ops_list,
9058
                          &missed_snapinfo->snap_ops);
9059
        cds_list_add_tail(&missed_snapinfo->missed_snaps,
9060
                          &priv->missed_snaps_list);
9061

9062
        ret = 0;
9063
        goto out;
9064
    } else {
9065
        ret = glusterd_update_missed_snap_entry(missed_snapinfo,
9066
                                                missed_snap_op);
9067
        if (ret) {
9068
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL,
9069
                   "Failed to update existing missed snap entry.");
9070
            goto out;
9071
        }
9072
    }
9073

9074
out:
9075
    if (ret) {
9076
        glusterd_free_snap_op(missed_snap_op);
9077

9078
        if (missed_snapinfo && (free_missed_snap_info == _gf_true))
9079
            glusterd_free_missed_snapinfo(missed_snapinfo);
9080
    }
9081

9082
    gf_msg_trace(this->name, 0, "Returning %d", ret);
9083
    return ret;
9084
}
9085

9086
/* Add  missing snap entries to the in-memory conf->missed_snap_list */
9087
int32_t
9088
glusterd_add_missed_snaps_to_list(dict_t *dict, int32_t missed_snap_count)
9089
{
9090
    char *buf = NULL;
9091
    char *tmp = NULL;
9092
    char *save_ptr = NULL;
9093
    char *nodeid = NULL;
9094
    char *snap_uuid = NULL;
9095
    char *snap_vol_id = NULL;
9096
    char *brick_path = NULL;
9097
    char missed_info[PATH_MAX] = "";
9098
    char key[64] = "";
9099
    int keylen;
9100
    int32_t i = -1;
9101
    int32_t ret = -1;
9102
    int32_t brick_num = -1;
9103
    int32_t snap_op = -1;
9104
    int32_t snap_status = -1;
9105
    glusterd_conf_t *priv = NULL;
9106
    xlator_t *this = THIS;
9107

9108
    GF_ASSERT(dict);
9109

9110
    priv = this->private;
9111
    GF_ASSERT(priv);
9112

9113
    /* We can update the missed_snaps_list without acquiring *
9114
     * any additional locks as big lock will be held.        */
9115
    for (i = 0; i < missed_snap_count; i++) {
9116
        keylen = snprintf(key, sizeof(key), "missed_snaps_%d", i);
9117
        ret = dict_get_strn(dict, key, keylen, &buf);
9118
        if (ret) {
9119
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
9120
                   "Unable to fetch %s", key);
9121
            goto out;
9122
        }
9123

9124
        gf_msg_debug(this->name, 0, "missed_snap_entry = %s", buf);
9125

9126
        /* Need to make a duplicate string coz the same dictionary *
9127
         * is resent to the non-originator nodes */
9128
        tmp = gf_strdup(buf);
9129
        if (!tmp) {
9130
            ret = -1;
9131
            goto out;
9132
        }
9133

9134
        /* Fetch the node-id, snap-id, brick_num,
9135
         * brick_path, snap_op and snap status
9136
         */
9137
        nodeid = strtok_r(tmp, ":", &save_ptr);
9138
        snap_uuid = strtok_r(NULL, "=", &save_ptr);
9139
        snap_vol_id = strtok_r(NULL, ":", &save_ptr);
9140
        brick_num = atoi(strtok_r(NULL, ":", &save_ptr));
9141
        brick_path = strtok_r(NULL, ":", &save_ptr);
9142
        snap_op = atoi(strtok_r(NULL, ":", &save_ptr));
9143
        snap_status = atoi(strtok_r(NULL, ":", &save_ptr));
9144

9145
        if (!nodeid || !snap_uuid || !brick_path || !snap_vol_id ||
9146
            brick_num < 1 || snap_op < 1 || snap_status < 1) {
9147
            gf_msg(this->name, GF_LOG_ERROR, 0,
9148
                   GD_MSG_INVALID_MISSED_SNAP_ENTRY,
9149
                   "Invalid missed_snap_entry");
9150
            ret = -1;
9151
            goto out;
9152
        }
9153

9154
        snprintf(missed_info, sizeof(missed_info), "%s:%s", nodeid, snap_uuid);
9155

9156
        ret = glusterd_add_new_entry_to_list(missed_info, snap_vol_id,
9157
                                             brick_num, brick_path, snap_op,
9158
                                             snap_status);
9159
        if (ret) {
9160
            gf_msg(this->name, GF_LOG_ERROR, 0,
9161
                   GD_MSG_MISSED_SNAP_LIST_STORE_FAIL,
9162
                   "Failed to store missed snaps_list");
9163
            goto out;
9164
        }
9165

9166
        GF_FREE(tmp);
9167
        tmp = NULL;
9168
    }
9169

9170
    ret = 0;
9171
out:
9172
    if (tmp)
9173
        GF_FREE(tmp);
9174

9175
    gf_msg_trace(this->name, 0, "Returning %d", ret);
9176
    return ret;
9177
}
9178

9179
int32_t
9180
glusterd_bricks_snapshot_restore(dict_t *rsp_dict, glusterd_volinfo_t *snap_vol,
9181
                                 gf_boolean_t *retain_origin_path)
9182
{
9183
    int32_t brick_count = -1;
9184
    int32_t ret = -1;
9185
    int32_t err = 0;
9186
    glusterd_brickinfo_t *brickinfo = NULL;
9187
    char snap_volume_id[64] = "";
9188
    xlator_t *this = NULL;
9189
    struct glusterd_snap_ops *snap_ops = NULL;
9190

9191
    this = THIS;
9192
    GF_ASSERT(this);
9193
    GF_ASSERT(snap_vol);
9194

9195
    brick_count = -1;
9196
    glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
9197

9198
    cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
9199
    {
9200
        brick_count++;
9201
        if (gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
9202
            gf_msg_debug(this->name, 0, "%s:%s belongs to a different node",
9203
                         brickinfo->hostname, brickinfo->path);
9204
            continue;
9205
        }
9206

9207
        GLUSTERD_GET_UUID_NOHYPHEN(snap_volume_id, snap_vol->volume_id);
9208
        ret = snap_ops->restore(brickinfo, snap_vol->snapshot->snapname,
9209
                                snap_volume_id, brick_count,
9210
                                retain_origin_path);
9211
        if (ret) {
9212
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
9213
                   "Failed to "
9214
                   "restore the snapshot %s (%s)",
9215
                   brickinfo->path, snap_vol->snapshot->snapname);
9216
            err = -1; /* We need to record this failure */
9217
        }
9218
    }
9219

9220
    ret = 0;
9221

9222
    if (err) {
9223
        ret = err;
9224
    }
9225
    gf_msg_trace(this->name, 0, "Returning %d", ret);
9226
    return ret;
9227
}
9228

9229
/* This function will restore origin volume to it's snap.
9230
 * The restore operation will simply replace the Gluster origin
9231
 * volume with the snap volume.
9232
 * TODO: Multi-volume delete to be done.
9233
 *       Cleanup in case of restore failure is pending.
9234
 *
9235
 * @param orig_vol      volinfo of origin volume
9236
 * @param snap_vol      volinfo of snapshot volume
9237
 *
9238
 * @return 0 on success and negative value on error
9239
 */
9240
int
9241
gd_restore_snap_volume(dict_t *dict, dict_t *rsp_dict,
9242
                       glusterd_volinfo_t *orig_vol,
9243
                       glusterd_volinfo_t *snap_vol, int32_t volcount,
9244
                       gf_boolean_t retain_origin_path)
9245
{
9246
    int ret = -1;
9247
    glusterd_volinfo_t *new_volinfo = NULL;
9248
    glusterd_snap_t *snap = NULL;
9249
    xlator_t *this = THIS;
9250
    glusterd_conf_t *conf = NULL;
9251
    glusterd_volinfo_t *temp_volinfo = NULL;
9252
    glusterd_volinfo_t *voliter = NULL;
9253
    gf_boolean_t conf_present = _gf_false;
9254

9255
    GF_ASSERT(dict);
9256
    GF_ASSERT(rsp_dict);
9257
    conf = this->private;
9258
    GF_ASSERT(conf);
9259

9260
    GF_VALIDATE_OR_GOTO(this->name, orig_vol, out);
9261
    GF_VALIDATE_OR_GOTO(this->name, snap_vol, out);
9262
    snap = snap_vol->snapshot;
9263
    GF_VALIDATE_OR_GOTO(this->name, snap, out);
9264

9265
    /* Set the status to under restore so that if the
9266
     * the node goes down during restore and comes back
9267
     * the state of the volume can be reverted correctly
9268
     */
9269
    snap->snap_status = GD_SNAP_STATUS_UNDER_RESTORE;
9270

9271
    /* We need to save this in disk so that if node goes
9272
     * down the status is in updated state.
9273
     */
9274
    ret = glusterd_store_snap(snap);
9275
    if (ret) {
9276
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED,
9277
               "Could not store snap "
9278
               "object for %s snap of %s volume",
9279
               snap_vol->volname, snap_vol->parent_volname);
9280
        goto out;
9281
    }
9282

9283
    /* Snap volume must be stopped before performing the
9284
     * restore operation.
9285
     */
9286
    ret = glusterd_stop_volume(snap_vol);
9287
    if (ret) {
9288
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_STOP_FAILED,
9289
               "Failed to stop "
9290
               "snap volume");
9291
        goto out;
9292
    }
9293

9294
    /* Create a new volinfo for the restored volume */
9295
    ret = glusterd_volinfo_dup(snap_vol, &new_volinfo, _gf_true);
9296
    if (ret) {
9297
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
9298
               "Failed to create volinfo");
9299
        goto out;
9300
    }
9301

9302
    /* Following entries need to be derived from origin volume. */
9303
    gf_strncpy(new_volinfo->volname, orig_vol->volname,
9304
               sizeof(new_volinfo->volname));
9305
    gf_uuid_copy(new_volinfo->volume_id, orig_vol->volume_id);
9306
    new_volinfo->snap_count = orig_vol->snap_count;
9307
    gf_uuid_copy(new_volinfo->restored_from_snap, snap_vol->snapshot->snap_id);
9308
    strcpy(new_volinfo->restored_from_snapname_id, snap_vol->volname);
9309
    strcpy(new_volinfo->restored_from_snapname, snap_vol->snapshot->snapname);
9310

9311
    /* Use the same version as the original version */
9312
    new_volinfo->version = orig_vol->version;
9313

9314
    /* Copy the snap vol info to the new_volinfo.*/
9315
    ret = glusterd_snap_volinfo_restore(dict, rsp_dict, new_volinfo, snap_vol,
9316
                                        volcount, retain_origin_path,
9317
                                        snap_mount_dir);
9318
    if (ret) {
9319
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
9320
               "Failed to restore snap");
9321
        goto out;
9322
    }
9323

9324
    /* In case a new node is added to the peer, after a snapshot was
9325
     * taken, the geo-rep files are not synced to that node. This
9326
     * leads to the failure of snapshot restore. Hence, ignoring the
9327
     * missing geo-rep files in the new node, and proceeding with
9328
     * snapshot restore. Once the restore is successful, the missing
9329
     * geo-rep files can be generated with "gluster volume geo-rep
9330
     * <primary-vol> <secondary-vol> create push-pem force"
9331
     */
9332
    ret = glusterd_restore_geo_rep_files(snap_vol);
9333
    if (ret) {
9334
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
9335
               "Failed to restore "
9336
               "geo-rep files for snap %s",
9337
               snap_vol->snapshot->snapname);
9338
    }
9339

9340
    /* Need not save cksum, as we will copy cksum file in *
9341
     * this function                                           *
9342
     */
9343
    ret = glusterd_copy_quota_files(snap_vol, orig_vol, &conf_present);
9344
    if (ret) {
9345
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
9346
               "Failed to restore "
9347
               "quota files for snap %s",
9348
               snap_vol->snapshot->snapname);
9349
        goto out;
9350
    }
9351

9352
    /* New volinfo always shows the status as created. Therefore
9353
     * set the status to the original volume's status. */
9354
    glusterd_set_volume_status(new_volinfo, orig_vol->status);
9355

9356
    cds_list_add_tail(&new_volinfo->vol_list, &conf->volumes);
9357

9358
    ret = glusterd_store_volinfo(new_volinfo,
9359
                                 GLUSTERD_VOLINFO_VER_AC_INCREMENT);
9360
    if (ret) {
9361
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
9362
               "Failed to store volinfo");
9363
        goto out;
9364
    }
9365

9366
    ret = 0;
9367
out:
9368
    if (ret) {
9369
        /* In case of any failure we should free new_volinfo. Doing
9370
         * this will also remove the entry we added in conf->volumes
9371
         * if it was added there.
9372
         */
9373
        if (new_volinfo)
9374
            (void)glusterd_volinfo_unref(new_volinfo);
9375
    } else {
9376
        cds_list_for_each_entry_safe(voliter, temp_volinfo,
9377
                                     &orig_vol->snap_volumes, snapvol_list)
9378
        {
9379
            cds_list_add_tail(&voliter->snapvol_list,
9380
                              &new_volinfo->snap_volumes);
9381
        }
9382
    }
9383

9384
    return ret;
9385
}
9386

9387
int
9388
glusterd_snapshot_get_volnames_uuids(dict_t *dict, char *volname,
9389
                                     gf_getsnap_name_uuid_rsp *snap_info_rsp)
9390
{
9391
    int ret = -1;
9392
    int snapcount = 0;
9393
    char key[32] = "";
9394
    glusterd_volinfo_t *snap_vol = NULL;
9395
    glusterd_volinfo_t *volinfo = NULL;
9396
    glusterd_volinfo_t *tmp_vol = NULL;
9397
    xlator_t *this = THIS;
9398
    int op_errno = 0;
9399

9400
    GF_ASSERT(volname);
9401
    GF_VALIDATE_OR_GOTO_WITH_ERROR(this->name, dict, out, op_errno, EINVAL);
9402
    GF_VALIDATE_OR_GOTO_WITH_ERROR(this->name, volname, out, op_errno, EINVAL);
9403
    GF_VALIDATE_OR_GOTO_WITH_ERROR(this->name, snap_info_rsp, out, op_errno,
9404
                                   EINVAL);
9405

9406
    ret = glusterd_volinfo_find(volname, &volinfo);
9407
    if (ret) {
9408
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
9409
               "Failed to get volinfo of volume %s", volname);
9410
        op_errno = EINVAL;
9411
        goto out;
9412
    }
9413

9414
    cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
9415
                                 snapvol_list)
9416
    {
9417
        if (GLUSTERD_STATUS_STARTED != snap_vol->status)
9418
            continue;
9419

9420
        snapcount++;
9421

9422
        /* Set Snap Name */
9423
        snprintf(key, sizeof(key), "snapname.%d", snapcount);
9424
        ret = dict_set_dynstr_with_alloc(dict, key,
9425
                                         snap_vol->snapshot->snapname);
9426
        if (ret) {
9427
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9428
                   "Failed to set "
9429
                   "snap name in dictionary");
9430
            goto out;
9431
        }
9432

9433
        /* Set Snap ID */
9434
        snprintf(key, sizeof(key), "snap-id.%d", snapcount);
9435
        ret = dict_set_dynstr_with_alloc(
9436
            dict, key, uuid_utoa(snap_vol->snapshot->snap_id));
9437
        if (ret) {
9438
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9439
                   "Failed to set "
9440
                   "snap id in dictionary");
9441
            goto out;
9442
        }
9443

9444
        /* Snap Volname which is used to activate the snap vol */
9445
        snprintf(key, sizeof(key), "snap-volname.%d", snapcount);
9446
        ret = dict_set_dynstr_with_alloc(dict, key, snap_vol->volname);
9447
        if (ret) {
9448
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9449
                   "Failed to set "
9450
                   "snap id in dictionary");
9451
            goto out;
9452
        }
9453
    }
9454

9455
    ret = dict_set_int32_sizen(dict, "snap-count", snapcount);
9456
    if (ret) {
9457
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9458
               "Failed to set snapcount");
9459
        op_errno = -ret;
9460
        goto out;
9461
    }
9462

9463
    ret = dict_allocate_and_serialize(dict, &snap_info_rsp->dict.dict_val,
9464
                                      &snap_info_rsp->dict.dict_len);
9465
    if (ret) {
9466
        op_errno = -ret;
9467
        ret = -1;
9468
        goto out;
9469
    }
9470

9471
    ret = 0;
9472

9473
out:
9474
    snap_info_rsp->op_ret = ret;
9475
    snap_info_rsp->op_errno = op_errno;
9476
    snap_info_rsp->op_errstr = "";
9477

9478
    return ret;
9479
}
9480

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

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

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

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