2
Copyright (c) 2013-2014 Red Hat, Inc. <http://www.redhat.com>
3
This file is part of GlusterFS.
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.
13
#include <sys/statvfs.h>
16
#include "glusterd-messages.h"
17
#include "glusterd-errno.h"
19
#if defined(GF_LINUX_HOST_OS)
22
#include "mntent_compat.h"
26
#define umount2(dir, flags) unmount(dir, ((flags) != 0) ? MNT_FORCE : 0)
29
#if defined(GF_DARWIN_HOST_OS) || defined(__FreeBSD__)
32
#define umount2(dir, flags) unmount(dir, ((flags) != 0) ? MNT_FORCE : 0)
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"
52
#include "glusterfs3.h"
54
#include <glusterfs/syscall.h>
56
#include <glusterfs/events.h>
58
char snap_mount_dir[VALID_GLUSTERD_PATHMAX];
59
struct snap_create_args_ {
63
glusterd_volinfo_t *snap_vol;
64
glusterd_brickinfo_t *brickinfo;
65
struct syncargs *args;
71
/* This structure is used to store unsupported options and their values
72
* for snapshotted volume.
74
struct gd_snap_unsupported_opt_t {
79
typedef struct snap_create_args_ snap_create_args_t;
81
/* Look for disconnected peers, for missed snap creates or deletes */
83
glusterd_find_missed_snap(dict_t *rsp_dict, glusterd_volinfo_t *vol,
84
struct cds_list_head *peers, int32_t op)
86
int32_t brick_count = -1;
88
xlator_t *this = THIS;
89
glusterd_peerinfo_t *peerinfo = NULL;
90
glusterd_brickinfo_t *brickinfo = NULL;
97
cds_list_for_each_entry(brickinfo, &vol->bricks, brick_list)
99
if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
100
/* If the brick belongs to the same node */
106
cds_list_for_each_entry_rcu(peerinfo, peers, uuid_list)
108
if (gf_uuid_compare(peerinfo->uuid, brickinfo->uuid)) {
109
/* If the brick doesn't belong to this peer */
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);
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 "
127
brickinfo->hostname, brickinfo->path);
138
gf_msg_trace(this->name, 0, "Returning %d", ret);
143
snap_max_limits_display_commit(dict_t *rsp_dict, char *volname, char *op_errstr,
146
char err_str[PATH_MAX] = "";
149
glusterd_conf_t *conf = NULL;
150
glusterd_volinfo_t *volinfo = NULL;
152
uint64_t active_hard_limit = 0;
153
uint64_t snap_max_limit = 0;
154
uint64_t soft_limit_value = -1;
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";
163
GF_ASSERT(op_errstr);
165
conf = this->private;
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
173
gd_get_snap_conf_values_if_present(conf->opts, &opt_hard_max,
177
/* For system limit */
178
cds_list_for_each_entry(volinfo, &conf->volumes, vol_list)
180
if (volinfo->is_snap_volume == _gf_true)
183
snap_max_limit = volinfo->snap_max_hard_limit;
184
if (snap_max_limit > opt_hard_max)
185
active_hard_limit = opt_hard_max;
187
active_hard_limit = snap_max_limit;
189
soft_limit_value = (opt_soft_max * active_hard_limit) / 100;
191
keylen = snprintf(key, sizeof(key), "volume%" PRId64 "-volname",
193
ret = dict_set_strn(rsp_dict, key, keylen, volinfo->volname);
195
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
197
strcpy(err_str, "<error>");
202
snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-hard-limit",
204
ret = dict_set_uint64(rsp_dict, key, snap_max_limit);
206
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
208
strcpy(err_str, "<error>");
213
snprintf(key, sizeof(key), "volume%" PRId64 "-active-hard-limit",
215
ret = dict_set_uint64(rsp_dict, key, active_hard_limit);
217
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
219
strcpy(err_str, "<error>");
224
snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-soft-limit",
226
ret = dict_set_uint64(rsp_dict, key, soft_limit_value);
228
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
230
strcpy(err_str, "<error>");
237
ret = dict_set_uint64(rsp_dict, "voldisplaycount", count);
239
snprintf(err_str, PATH_MAX, "Failed to set voldisplaycount");
244
ret = glusterd_volinfo_find(volname, &volinfo);
246
snprintf(err_str, PATH_MAX,
247
"Volume (%s) does not "
253
snap_max_limit = volinfo->snap_max_hard_limit;
254
if (snap_max_limit > opt_hard_max)
255
active_hard_limit = opt_hard_max;
257
active_hard_limit = snap_max_limit;
259
soft_limit_value = (opt_soft_max * active_hard_limit) / 100;
261
keylen = snprintf(key, sizeof(key), "volume%" PRId64 "-volname", count);
262
ret = dict_set_strn(rsp_dict, key, keylen, volinfo->volname);
264
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
266
strcpy(err_str, "<error>");
271
snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-hard-limit",
273
ret = dict_set_uint64(rsp_dict, key, snap_max_limit);
275
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
277
strcpy(err_str, "<error>");
282
snprintf(key, sizeof(key), "volume%" PRId64 "-active-hard-limit",
284
ret = dict_set_uint64(rsp_dict, key, active_hard_limit);
286
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
288
strcpy(err_str, "<error>");
293
snprintf(key, sizeof(key), "volume%" PRId64 "-snap-max-soft-limit",
295
ret = dict_set_uint64(rsp_dict, key, soft_limit_value);
297
len = snprintf(err_str, PATH_MAX, "Failed to set %s", key);
299
strcpy(err_str, "<error>");
306
ret = dict_set_uint64(rsp_dict, "voldisplaycount", count);
308
snprintf(err_str, PATH_MAX, "Failed to set voldisplaycount");
313
ret = dict_set_uint64(rsp_dict, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
316
snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
317
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
321
ret = dict_set_uint64(rsp_dict, GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT,
324
snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
325
GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT);
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.
333
ret = dict_get_str(conf->opts, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE,
336
ret = dict_set_dynstr_with_alloc(
337
rsp_dict, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, auto_delete);
339
snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
340
GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE);
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.
348
ret = dict_get_str(conf->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE,
351
ret = dict_set_dynstr_with_alloc(rsp_dict, GLUSTERD_STORE_KEY_SNAP_ACTIVATE,
354
snprintf(err_str, PATH_MAX, "Failed to set %s in response dictionary",
355
GLUSTERD_STORE_KEY_SNAP_ACTIVATE);
362
strncpy(op_errstr, err_str, len);
363
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "%s",
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.
375
file_select(const struct dirent *entry)
380
if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
387
glusterd_copy_geo_rep_session_files(char *session, glusterd_volinfo_t *snap_vol)
390
char snap_session_dir[PATH_MAX] = "";
391
char georep_session_dir[PATH_MAX] = "";
394
struct dirent **files = {
397
xlator_t *this = THIS;
399
char src_path[PATH_MAX] = "";
400
char dest_path[PATH_MAX] = "";
401
glusterd_conf_t *priv = NULL;
403
priv = this->private;
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);
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);
424
ret = mkdir_p(snap_session_dir, 0755, _gf_true);
426
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
427
"Creating directory %s failed", snap_session_dir);
431
ret = regcomp(®_exp, "(.*status$)|(.*conf$)\0", REG_EXTENDED);
433
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REG_COMPILE_FAILED,
434
"Failed to compile the regular expression");
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) {
442
gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
443
"Session files not present "
449
/* Now compare the file name with regular expression to see if
452
for (i = 0; i < file_count; i++) {
453
if (regexec(®_exp, files[i]->d_name, 0, NULL, 0))
456
ret = snprintf(src_path, sizeof(src_path), "%s/%s", georep_session_dir,
459
gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
463
ret = snprintf(dest_path, sizeof(dest_path), "%s/%s", snap_session_dir,
466
gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
470
ret = glusterd_copy_file(src_path, dest_path);
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,
483
/* files are malloc'd by scandir, free them */
484
if (file_count > 0) {
485
while (file_count--) {
486
free(files[file_count]);
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.
497
* @param volinfo volinfo of the origin volume
499
* @return 0 on success and -1 on failure
502
glusterd_snapshot_backup_vol(glusterd_volinfo_t *volinfo)
504
char pathname[PATH_MAX] = "";
507
char delete_path[PATH_MAX] = "";
508
char trashdir[PATH_MAX] = "";
509
glusterd_conf_t *priv = NULL;
510
xlator_t *this = THIS;
513
priv = this->private;
517
GLUSTERD_GET_VOLUME_DIR(pathname, volinfo, priv);
519
len = snprintf(delete_path, sizeof(delete_path),
520
"%s/" GLUSTERD_TRASH "/vols-%s.deleted", priv->workdir,
522
if ((len < 0) || (len >= sizeof(delete_path))) {
523
gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
527
len = snprintf(trashdir, sizeof(trashdir), "%s/" GLUSTERD_TRASH,
529
if ((len < 0) || (len >= sizeof(trashdir))) {
530
gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
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",
544
/* Move the origin volume volder to the backup location */
545
ret = sys_rename(pathname, delete_path);
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);
554
/* Re-create an empty origin volume folder so that restore can
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));
568
/* Save the actual return value */
571
/* Revert the changes in case of failure */
572
ret = sys_rmdir(pathname);
574
gf_msg_debug(this->name, errno, "Failed to rmdir: %s", pathname);
577
ret = sys_rename(delete_path, pathname);
579
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED,
580
"Failed to rename directory %s to %s", delete_path,
584
ret = sys_rmdir(trashdir);
586
gf_msg_debug(this->name, errno, "Failed to rmdir: %s", trashdir);
590
gf_msg_trace(this->name, 0, "Returning %d", op_ret);
596
glusterd_copy_geo_rep_files(glusterd_volinfo_t *origin_vol,
597
glusterd_volinfo_t *snap_vol, dict_t *rsp_dict)
601
xlator_t *this = THIS;
603
char session[PATH_MAX] = "";
604
char secondary[PATH_MAX] = "";
605
char snapgeo_dir[PATH_MAX] = "";
606
glusterd_conf_t *priv = NULL;
608
priv = this->private;
611
GF_ASSERT(origin_vol);
615
/* This condition is not satisfied if the volume
616
* is secondary volume.
618
if (!origin_vol->gsync_secondaries) {
619
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_SECONDARY,
625
GLUSTERD_GET_SNAP_GEO_REP_DIR(snapgeo_dir, snap_vol->snapshot, priv);
627
ret = sys_mkdir(snapgeo_dir, 0755);
629
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
630
"Creating directory %s failed", snapgeo_dir);
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 */
639
ret = glusterd_get_geo_rep_session(key, origin_vol->volname,
640
origin_vol->gsync_secondaries,
643
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GEOREP_GET_FAILED,
644
"Failed to get geo-rep session");
648
ret = glusterd_copy_geo_rep_session_files(session, snap_vol);
650
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED,
651
"Failed to copy files"
652
" related to session %s",
662
/* This function will restore a snapshot volumes
664
* @param dict dictionary containing snapshot restore request
665
* @param op_errstr In case of any failure error message will be returned
667
* @return Negative value on Failure and 0 in success
670
glusterd_snapshot_restore(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
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;
684
GF_ASSERT(op_errstr);
687
priv = this->private;
690
ret = dict_get_str(dict, "snapname", &snapname);
692
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
693
"Failed to get snap name");
697
snap = glusterd_find_snap_by_name(snapname);
699
ret = gf_asprintf(op_errstr, "Snapshot (%s) does not exist", snapname);
703
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND, "%s",
710
cds_list_for_each_entry_safe(snap_volinfo, tmp, &snap->volumes, vol_list)
713
ret = glusterd_volinfo_find(snap_volinfo->parent_volname,
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);
721
ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
722
uuid_utoa(snap->snap_id));
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",
731
ret = dict_set_dynstr_with_alloc(rsp_dict, "volname",
732
snap_volinfo->parent_volname);
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",
741
ret = dict_set_dynstr_with_alloc(rsp_dict, "volid",
742
uuid_utoa(parent_volinfo->volume_id));
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",
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,
756
GF_SNAP_OPTION_TYPE_RESTORE);
758
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_GET_FAIL,
759
"Failed to find missed snap restores");
764
/* During snapshot restore, mount point for stopped snap
765
* should exist as it is required to set extended attribute.
767
ret = glusterd_recreate_vol_brick_mounts(this, snap_volinfo);
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);
774
/* Call restore command for each bricks */
775
ret = glusterd_bricks_snapshot_restore(rsp_dict, snap_volinfo,
776
&retain_origin_path);
778
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
779
"Failed to restore snap");
783
ret = gd_restore_snap_volume(dict, rsp_dict, parent_volinfo,
784
snap_volinfo, volcount,
787
/* No need to update op_errstr because it is assumed
788
* that the called function will do that in case of
791
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
798
/* Detach the volinfo from priv->volumes, so that no new
799
* command can ref it any more and then unref it.
801
cds_list_del_init(&parent_volinfo->vol_list);
802
glusterd_volinfo_unref(parent_volinfo);
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.
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.
818
* @param dict dictionary containing snapshot restore request
819
* @param op_errstr In case of any failure error message will be returned
821
* @param rsp_dict response dictionary
822
* @return Negative value on Failure and 0 in success
825
glusterd_snapshot_restore_prevalidate(dict_t *dict, char **op_errstr,
826
uint32_t *op_errno, dict_t *rsp_dict)
830
int32_t volcount = 0;
831
int32_t brick_count = 0;
832
gf_boolean_t snap_restored = _gf_false;
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;
843
GF_ASSERT(op_errstr);
844
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
847
ret = dict_get_str(dict, "snapname", &snapname);
849
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
855
snap = glusterd_find_snap_by_name(snapname);
857
ret = gf_asprintf(op_errstr, "Snapshot (%s) does not exist", snapname);
858
*op_errno = EG_SNAPEXST;
862
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND, "%s",
868
snap_restored = snap->snap_restored;
871
ret = gf_asprintf(op_errstr,
872
"Snapshot (%s) is already "
878
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
884
ret = dict_set_str_sizen(rsp_dict, "snapname", snapname);
886
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
893
ret = dict_get_int32(dict, "volcount", &volcount);
896
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
897
"Failed to get volume count");
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);
907
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
913
ret = glusterd_volinfo_find(volname, &volinfo);
915
ret = gf_asprintf(op_errstr,
919
*op_errno = EG_NOVOL;
923
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND, "%s",
929
if (glusterd_is_volume_started(volinfo)) {
932
"Volume (%s) has been "
933
"started. Volume needs to be stopped before restoring "
936
*op_errno = EG_VOLRUN;
940
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
946
/* Take backup of the volinfo folder */
947
ret = glusterd_snapshot_backup_vol(volinfo);
949
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
951
"volume backend files for %s volume",
957
/* Get brickinfo for snap_volumes */
959
cds_list_for_each_entry(volinfo, &snap->volumes, vol_list)
964
cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
967
if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
970
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.path", volcount,
972
ret = dict_set_strn(rsp_dict, key, keylen, brickinfo->path);
974
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
975
"Failed to set %s", key);
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);
983
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
984
"Failed to set %s", key);
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);
993
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
994
"Failed to set %s", key);
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);
1002
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1003
"Failed to set %s", key);
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);
1011
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1012
"Failed to set %s", key);
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);
1020
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1021
"Failed to set %s", key);
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);
1029
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1030
"Failed to set %s", key);
1035
keylen = snprintf(key, sizeof(key), "snap%d.brick_count", volcount);
1036
ret = dict_set_int32n(rsp_dict, key, keylen, brick_count);
1038
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1039
"Failed to set %s", key);
1044
ret = dict_set_int32_sizen(rsp_dict, "volcount", volcount);
1046
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1047
"Failed to set %s", key);
1056
snap_max_hard_limits_validate(dict_t *dict, char *volname, uint64_t value,
1059
char err_str[PATH_MAX] = "";
1060
glusterd_conf_t *conf = NULL;
1061
glusterd_volinfo_t *volinfo = NULL;
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;
1068
GF_ASSERT(op_errstr);
1070
conf = this->private;
1075
ret = glusterd_volinfo_find(volname, &volinfo);
1077
if (volinfo->is_snap_volume) {
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.",
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.
1093
ret = dict_get_uint64(conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
1097
gf_msg_debug(this->name, 0,
1098
"%s is not present in "
1100
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
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).
1108
if (value && volname) {
1109
max_limit = opt_hard_max;
1112
if (value > max_limit) {
1114
snprintf(err_str, PATH_MAX,
1115
"Invalid snap-max-hard-limit "
1116
"%" PRIu64 ". Expected range 1 - %" PRIu64,
1124
*op_errstr = gf_strdup(err_str);
1125
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
1132
glusterd_snapshot_config_prevalidate(dict_t *dict, char **op_errstr,
1135
char *volname = NULL;
1136
glusterd_volinfo_t *volinfo = NULL;
1137
xlator_t *this = THIS;
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;
1152
GF_ASSERT(op_errstr);
1153
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
1155
conf = this->private;
1159
ret = dict_get_int32(dict, "config-command", &config_command);
1161
snprintf(err_str, sizeof(err_str), "failed to get config-command type");
1165
if (config_command != GF_SNAP_CONFIG_TYPE_SET) {
1170
ret = dict_get_str(dict, "volname", &volname);
1172
ret = glusterd_volinfo_find(volname, &volinfo);
1174
snprintf(err_str, sizeof(err_str), "Volume (%s) does not exist.",
1176
*op_errno = EG_NOVOL;
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
1185
gd_get_snap_conf_values_if_present(dict, &hard_limit, &soft_limit);
1188
/* Validations for snap-max-hard-limits */
1189
ret = snap_max_hard_limits_validate(dict, volname, hard_limit,
1192
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HARD_LIMIT_SET_FAIL,
1193
"snap-max-hard-limit validation failed.");
1200
max_limit = GLUSTERD_SNAPS_MAX_SOFT_LIMIT_PERCENT;
1201
if (soft_limit > max_limit) {
1203
snprintf(err_str, PATH_MAX,
1205
"snap-max-soft-limit "
1206
"%" PRIu64 ". Expected range 1 - %" PRIu64,
1207
soft_limit, max_limit);
1213
if (hard_limit || soft_limit) {
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) {
1223
snprintf(err_str, sizeof(err_str),
1225
"valid boolean value for auto-delete");
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);
1235
if (cur_auto_delete == req_auto_delete) {
1237
if (cur_auto_delete == _gf_true)
1238
snprintf(err_str, sizeof(err_str),
1239
"auto-delete is already enabled");
1241
snprintf(err_str, sizeof(err_str),
1242
"auto-delete is already disabled");
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) {
1251
snprintf(err_str, sizeof(err_str),
1253
"valid boolean value for activate-on-create");
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);
1263
if (cur_snap_activate == req_snap_activate) {
1265
if (cur_snap_activate == _gf_true)
1266
snprintf(err_str, sizeof(err_str),
1267
"activate-on-create is already enabled");
1269
snprintf(err_str, sizeof(err_str),
1270
"activate-on-create is already disabled");
1276
snprintf(err_str, sizeof(err_str), "Invalid option");
1284
if (ret && err_str[0] != '\0') {
1285
gf_msg(this->name, loglevel, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
1287
*op_errstr = gf_strdup(err_str);
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.
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
1304
glusterd_handle_snapshot_config(rpcsvc_request_t *req, glusterd_op_t op,
1305
dict_t *dict, char *err_str, size_t len)
1308
char *volname = NULL;
1309
xlator_t *this = THIS;
1310
int config_command = 0;
1312
GF_VALIDATE_OR_GOTO(this->name, req, out);
1313
GF_VALIDATE_OR_GOTO(this->name, dict, out);
1315
/* TODO : Type of lock to be taken when we are setting
1316
* limits system wide
1318
ret = dict_get_int32(dict, "config-command", &config_command);
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);
1326
ret = dict_get_str(dict, "volname", &volname);
1328
switch (config_command) {
1329
case GF_SNAP_CONFIG_TYPE_SET:
1331
ret = dict_set_int32_sizen(dict, "hold_vol_locks", _gf_false);
1333
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1334
"Unable to set hold_vol_locks value "
1339
ret = glusterd_mgmt_v3_initiate_all_phases(req, op, dict);
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);
1345
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HARD_LIMIT_SET_FAIL,
1347
"display commit failed.");
1351
/* If everything is successful then send the response
1354
ret = glusterd_op_send_cli_response(op, 0, 0, req, dict, err_str);
1356
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
1357
"Failed to send cli "
1364
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
1365
"Unknown config type");
1373
glusterd_snap_create_clone_pre_val_use_rsp_dict(dict_t *dst, dict_t *src)
1375
char *snap_brick_dir = NULL;
1376
char *snap_device = NULL;
1380
char snapbrckcnt[PATH_MAX] = "";
1381
char snapbrckord[PATH_MAX] = "";
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;
1394
ret = dict_get_int64(src, "volcount", &volume_count);
1396
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1398
"get the volume count");
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);
1407
gf_msg_trace(this->name, 0,
1408
"No bricks for this volume in this dict");
1412
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_plugin",
1414
ret = dict_get_strn(src, key, keylen, &value);
1416
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1417
"Unable to fetch %s", key);
1421
ret = dict_set_dynstr_with_alloc(dst, key, value);
1423
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1424
"Failed to set %s", key);
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,
1432
ret = dict_get_ptr(src, key, (void **)&snap_brick_dir);
1434
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1435
"Unable to fetch %s", key);
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);
1444
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1445
"Failed to get brick order");
1449
snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%" PRId64, i + 1,
1451
ret = dict_set_dynstr_with_alloc(dst, key, snap_brick_dir);
1453
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1454
"Failed to set %s", key);
1458
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%" PRId64,
1460
ret = dict_get_strn(src, key, keylen, &value);
1462
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1463
"Unable to fetch %s", key);
1467
snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%" PRId64, i + 1,
1469
ret = dict_set_dynstr_with_alloc(dst, key, value);
1471
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1472
"Failed to set %s", key);
1476
keylen = snprintf(key, sizeof(key),
1477
"vol%" PRId64 ".snap_type%" PRId64, i + 1, j);
1478
ret = dict_get_strn(src, key, keylen, &value);
1480
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1481
"Unable to fetch %s", key);
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);
1489
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1490
"Failed to set %s", key);
1494
keylen = snprintf(key, sizeof(key),
1495
"vol%" PRId64 ".mnt_opts%" PRId64, i + 1, j);
1496
ret = dict_get_strn(src, key, keylen, &value);
1498
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1499
"Unable to fetch %s", key);
1503
snprintf(key, sizeof(key), "vol%" PRId64 ".mnt_opts%" PRId64, i + 1,
1505
ret = dict_set_dynstr_with_alloc(dst, key, value);
1507
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1508
"Failed to set %s", key);
1512
snprintf(key, sizeof(key),
1513
"vol%" PRId64 ".brick_snapdevice%" PRId64, i + 1, j);
1514
ret = dict_get_ptr(src, key, (void **)&snap_device);
1516
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1517
"Unable to fetch snap_device");
1521
snprintf(key, sizeof(key),
1522
"vol%" PRId64 ".brick_snapdevice%" PRId64, i + 1,
1524
ret = dict_set_dynstr_with_alloc(dst, key, snap_device);
1526
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1527
"Failed to set %s", key);
1531
keylen = snprintf(key, sizeof(key),
1532
"vol%" PRId64 ".brick%" PRId64 ".status", i + 1,
1534
ret = dict_get_int32n(src, key, keylen, &brick_online);
1536
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1538
"get the brick status");
1542
ret = dict_set_int32n(dst, key, keylen, brick_online);
1544
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1546
"set the brick status");
1555
gf_msg_trace(this->name, 0, "Returning %d", ret);
1559
/* Aggregate brickinfo's of the snap volumes to be restored from */
1561
glusterd_snap_restore_use_rsp_dict(dict_t *dst, dict_t *src)
1565
char *strvalue = NULL;
1569
int32_t vol_count = -1;
1570
int32_t brickcount = -1;
1572
xlator_t *this = THIS;
1575
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
1576
"Source or Destination "
1581
ret = dict_get_int32(src, "volcount", &vol_count);
1583
gf_msg_debug(this->name, 0, "No volumes");
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);
1592
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1593
"Failed to get %s", key);
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);
1601
/* The brickinfo will be present in
1602
* another rsp_dict */
1603
gf_msg_debug(this->name, 0, "%s not present", key);
1607
ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1609
gf_msg_debug(this->name, 0, "Failed to set %s", key);
1613
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.snap_status", i,
1615
ret = dict_get_int32n(src, key, keylen, &value);
1617
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1618
"Failed to get %s", key);
1621
ret = dict_set_int32n(dst, key, keylen, value);
1623
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1624
"Failed to set %s", key);
1628
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.origin_path", i,
1630
ret = dict_get_strn(src, key, keylen, &strvalue);
1632
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1633
"Failed to get %s", key);
1636
ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1638
gf_msg_debug(this->name, 0, "Failed to set %s", key);
1642
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.device_path", i,
1644
ret = dict_get_strn(src, key, keylen, &strvalue);
1646
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1647
"Failed to get %s", key);
1649
ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1651
gf_msg_debug(this->name, 0, "Failed to set %s", key);
1656
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.fs_type", i, j);
1657
ret = dict_get_strn(src, key, keylen, &strvalue);
1659
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1660
"Failed to get %s", key);
1663
ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1665
gf_msg_debug(this->name, 0, "Failed to set %s", key);
1669
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.snap_type", i,
1671
ret = dict_get_strn(src, key, keylen, &strvalue);
1673
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1674
"Failed to get %s", key);
1677
ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1679
gf_msg_debug(this->name, 0, "Failed to set %s", key);
1683
keylen = snprintf(key, sizeof(key), "snap%d.brick%d.mnt_opts", i,
1685
ret = dict_get_strn(src, key, keylen, &strvalue);
1687
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1688
"Failed to get %s", key);
1691
ret = dict_set_dynstr_with_alloc(dst, key, strvalue);
1693
gf_msg_debug(this->name, 0, "Failed to set %s", key);
1700
gf_msg_trace(this->name, 0, "Returning %d", ret);
1705
glusterd_snap_pre_validate_use_rsp_dict(dict_t *dst, dict_t *src)
1708
int32_t snap_command = 0;
1709
xlator_t *this = THIS;
1712
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
1713
"Source or Destination "
1718
ret = dict_get_int32(dst, "type", &snap_command);
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");
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);
1731
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
1737
case GF_SNAP_OPTION_TYPE_RESTORE:
1738
ret = glusterd_snap_restore_use_rsp_dict(dst, src);
1740
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_RSP_DICT_USE_FAIL,
1752
gf_msg_debug(this->name, 0, "Returning %d", ret);
1757
glusterd_add_brick_status_to_dict(dict_t *dict, glusterd_volinfo_t *volinfo,
1758
glusterd_brickinfo_t *brickinfo,
1761
char pidfile[PATH_MAX] = "";
1762
int32_t brick_online = 0;
1764
xlator_t *this = THIS;
1765
glusterd_conf_t *conf = NULL;
1770
GF_ASSERT(brickinfo);
1772
conf = this->private;
1776
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
1777
"key prefix is NULL");
1781
GLUSTERD_GET_BRICK_PIDFILE(pidfile, volinfo, brickinfo, conf);
1783
brick_online = gf_is_service_running(pidfile, &pid);
1785
ret = dict_set_int32(dict, key_prefix, brick_online);
1787
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1788
"Failed to set %s", key_prefix);
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)
1805
char device[NAME_MAX] = "";
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;
1815
conf = this->private;
1817
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
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");
1827
cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
1829
if (gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
1834
if (!glusterd_is_brick_started(brickinfo)) {
1836
snprintf(err_str, PATH_MAX,
1837
"One or more bricks are not running. "
1838
"Please run volume status command to see "
1840
"All bricks have to be online to take a snapshot."
1841
"Please start the stopped brick "
1842
"and then issue snapshot create command.");
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.",
1851
snprintf(err_str, PATH_MAX,
1852
"One or more bricks are not running. "
1853
"Please run snapshot status command to see "
1855
"Please start the stopped brick "
1856
"and then issue snapshot clone "
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.",
1865
*op_errno = EG_BRCKDWN;
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.",
1879
snprintf(key, sizeof(key), "vol%" PRId64 ".snap_plugin", i);
1880
ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->snap->name);
1882
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1883
"Failed to set %s", key);
1887
snprintf(device, sizeof(device), "%s_%" PRId64, snap_volname,
1889
snprintf(key, sizeof(key), "vol%" PRId64 ".brick_snapdevice%" PRId64, i,
1891
ret = dict_set_dynstr_with_alloc(rsp_dict, key, device);
1893
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1894
"Failed to set %s", key);
1898
ret = glusterd_update_mntopts(brickinfo->path, brickinfo);
1900
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRK_MOUNTOPTS_FAIL,
1902
"update mount options for %s brick",
1906
snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%" PRId64, i,
1908
ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->fstype);
1910
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1911
"Failed to set %s", key);
1915
snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%" PRId64, i,
1917
ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->snap_type);
1919
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1920
"Failed to set %s", key);
1924
snprintf(key, sizeof(key), "vol%" PRId64 ".mnt_opts%" PRId64, i,
1926
ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->mnt_opts);
1928
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1929
"Failed to set %s", key);
1933
snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%" PRId64, i,
1935
ret = dict_set_dynstr_with_alloc(rsp_dict, key, brickinfo->mount_dir);
1937
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1938
"Failed to set %s", key);
1942
snprintf(key, sizeof(key) - 1, "vol%" PRId64 ".brick%" PRId64 ".order",
1944
ret = dict_set_int64(rsp_dict, key, brick_order);
1946
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1947
"Failed to set %s", key);
1951
snprintf(key, sizeof(key), "vol%" PRId64 ".brick%" PRId64 ".status", i,
1954
ret = glusterd_add_brick_status_to_dict(rsp_dict, volinfo, brickinfo,
1957
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1959
"add brick status to dict");
1965
snprintf(key, sizeof(key) - 1, "vol%" PRId64 "_brickcount", volcount);
1966
ret = dict_set_int64(rsp_dict, key, brick_count);
1968
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1969
"Failed to set %s", key);
1979
glusterd_snapshot_clone_prevalidate(dict_t *dict, char **op_errstr,
1980
dict_t *rsp_dict, uint32_t *op_errno)
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] = "";
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;
1995
GF_ASSERT(op_errstr);
1997
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
1999
ret = dict_get_str(dict, "clonename", &clonename);
2001
snprintf(err_str, sizeof(err_str),
2003
"get the clone name");
2007
ret = dict_get_str(dict, "snapname", &snapname);
2009
snprintf(err_str, sizeof(err_str), "Failed to get snapname");
2013
ret = glusterd_volinfo_find(clonename, &volinfo);
2016
snprintf(err_str, sizeof(err_str),
2017
"Volume with name:%s "
2020
*op_errno = EG_VOLEXST;
2023
/* need to find snap volinfo*/
2024
snap = glusterd_find_snap_by_name(snapname);
2027
snprintf(err_str, sizeof(err_str),
2028
"Failed to find :%s "
2034
/* TODO : As of now there is only one volume in snapshot.
2035
* Change this when multiple volume snapshot is introduced
2037
snap_vol = list_entry(snap->volumes.next, glusterd_volinfo_t, vol_list);
2039
gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
2040
"Failed to get snap "
2046
if (!glusterd_is_volume_started(snap_vol)) {
2047
snprintf(err_str, sizeof(err_str),
2051
loglevel = GF_LOG_WARNING;
2052
*op_errno = EG_VOLSTP;
2056
ret = dict_get_bin(dict, "vol1_volid", (void **)&snap_volid);
2058
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2059
"Unable to fetch snap_volid");
2063
GLUSTERD_GET_UUID_NOHYPHEN(device_name, *snap_volid);
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,
2070
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PRE_VALIDATION_FAIL,
2071
"Failed to pre validate");
2075
ret = dict_set_int64(rsp_dict, "volcount", volcount);
2077
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2078
"Failed to set volcount");
2084
if (ret && err_str[0] != '\0') {
2085
gf_msg(this->name, loglevel, 0, GD_MSG_SNAP_CLONE_PREVAL_FAILED, "%s",
2087
*op_errstr = gf_strdup(err_str);
2090
gf_msg_trace(this->name, 0, "Returning %d", ret);
2095
* gd_vol_is_geo_rep_active:
2096
* This function checks for any running geo-rep session for
2100
* _gf_true : If any running geo-rep session.
2101
* _gf_false: If no running geo-rep session.
2105
gd_vol_is_geo_rep_active(glusterd_volinfo_t *volinfo)
2107
gf_boolean_t active = _gf_false;
2111
if (volinfo->gsync_active_secondaries &&
2112
volinfo->gsync_active_secondaries->count > 0)
2119
glusterd_snapshot_create_prevalidate(dict_t *dict, char **op_errstr,
2120
dict_t *rsp_dict, uint32_t *op_errno)
2122
char *volname = NULL;
2123
char *snapname = NULL;
2126
char snap_volname[64] = "";
2127
char err_str[PATH_MAX] = "";
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;
2138
uint64_t opt_hard_max = GLUSTERD_SNAPS_MAX_HARD_LIMIT;
2139
char *description = NULL;
2141
GF_ASSERT(op_errstr);
2142
conf = this->private;
2144
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
2146
ret = dict_get_int64(dict, "volcount", &volcount);
2148
snprintf(err_str, sizeof(err_str),
2150
"get the volume count");
2153
if (volcount <= 0) {
2154
snprintf(err_str, sizeof(err_str),
2155
"Invalid volume count %" PRId64 " supplied", volcount);
2160
ret = dict_get_str(dict, "snapname", &snapname);
2162
snprintf(err_str, sizeof(err_str), "Failed to get snapname");
2166
ret = dict_get_str(dict, "description", &description);
2167
if (description && !(*description)) {
2168
/* description should have a non-null value */
2170
snprintf(err_str, sizeof(err_str),
2171
"Snapshot cannot be "
2172
"created with empty description");
2176
ret = dict_get_int32(dict, "flags", &flags);
2178
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2179
"Unable to get flags");
2183
if (glusterd_find_snap_by_name(snapname)) {
2185
snprintf(err_str, sizeof(err_str),
2186
"Snapshot %s already "
2189
*op_errno = EG_SNAPEXST;
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);
2197
snprintf(err_str, sizeof(err_str), "failed to get volume name");
2200
ret = glusterd_volinfo_find(volname, &volinfo);
2202
snprintf(err_str, sizeof(err_str), "Volume (%s) does not exist ",
2204
*op_errno = EG_NOVOL;
2209
if (!glusterd_is_volume_started(volinfo)) {
2210
snprintf(err_str, sizeof(err_str),
2214
loglevel = GF_LOG_WARNING;
2215
*op_errno = EG_VOLSTP;
2219
if (glusterd_is_defrag_on(volinfo)) {
2220
snprintf(err_str, sizeof(err_str),
2221
"rebalance process is running for the "
2224
loglevel = GF_LOG_WARNING;
2225
*op_errno = EG_RBALRUN;
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.",
2235
loglevel = GF_LOG_WARNING;
2236
*op_errno = EG_GEOREPRUN;
2240
if (volinfo->is_snap_volume == _gf_true) {
2241
snprintf(err_str, sizeof(err_str), "Volume %s is a snap volume",
2243
loglevel = GF_LOG_WARNING;
2244
*op_errno = EG_ISSNAP;
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.
2252
ret = dict_get_uint64(
2253
conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, &opt_hard_max);
2256
gf_msg_debug(this->name, 0,
2257
"%s is not present "
2258
"in opts dictionary",
2259
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
2262
if (volinfo->snap_max_hard_limit < opt_hard_max)
2263
effective_max_limit = volinfo->snap_max_hard_limit;
2265
effective_max_limit = opt_hard_max;
2267
if (volinfo->snap_count >= effective_max_limit) {
2269
snprintf(err_str, sizeof(err_str),
2270
"The number of existing snaps has reached "
2271
"the effective maximum limit of %" PRIu64
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;
2281
snprintf(key, sizeof(key), "vol%" PRId64 "_volid", i);
2282
ret = dict_get_bin(dict, key, (void **)&snap_volid);
2284
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2285
"Unable to fetch snap_volid");
2289
/* snap volume uuid is used as snapshot name.
2290
This will avoid restrictions on snapshot names
2292
GLUSTERD_GET_UUID_NOHYPHEN(snap_volname, *snap_volid);
2294
ret = glusterd_snap_create_clone_common_prevalidate(
2295
rsp_dict, flags, snapname, err_str, snap_volname, i, volinfo,
2296
&loglevel, 0, op_errno);
2298
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PRE_VALIDATION_FAIL,
2299
"Failed to pre validate");
2304
ret = dict_set_int64(rsp_dict, "volcount", volcount);
2306
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2307
"Failed to set volcount");
2314
if (ret && err_str[0] != '\0') {
2315
gf_msg(this->name, loglevel, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
2317
*op_errstr = gf_strdup(err_str);
2320
gf_msg_trace(this->name, 0, "Returning %d", ret);
2325
glusterd_new_snap_object(void)
2327
glusterd_snap_t *snap = NULL;
2329
snap = GF_CALLOC(1, sizeof(*snap), gf_gld_mt_snap_t);
2332
if (LOCK_INIT(&snap->lock)) {
2333
gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_LOCK_INIT_FAILED,
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;
2349
/* Function glusterd_list_add_snapvol adds the volinfo object (snapshot volume)
2350
to the snapshot object list and to the parent volume list */
2352
glusterd_list_add_snapvol(glusterd_volinfo_t *origin_vol,
2353
glusterd_volinfo_t *snap_vol)
2356
glusterd_snap_t *snap = NULL;
2358
GF_VALIDATE_OR_GOTO("glusterd", origin_vol, out);
2359
GF_VALIDATE_OR_GOTO("glusterd", snap_vol, out);
2361
snap = snap_vol->snapshot;
2364
cds_list_add_tail(&snap_vol->vol_list, &snap->volumes);
2365
LOCK(&origin_vol->lock);
2367
glusterd_list_add_order(&snap_vol->snapvol_list,
2368
&origin_vol->snap_volumes,
2369
glusterd_compare_snap_vol_time);
2371
origin_vol->snap_count++;
2373
UNLOCK(&origin_vol->lock);
2375
gf_msg_debug(THIS->name, 0, "Snapshot %s added to the list",
2383
glusterd_find_snap_by_name(char *snapname)
2385
glusterd_snap_t *snap = NULL;
2386
glusterd_conf_t *priv = NULL;
2388
priv = THIS->private;
2390
GF_ASSERT(snapname);
2392
cds_list_for_each_entry(snap, &priv->snapshots, snap_list)
2394
if (!strcmp(snap->snapname, snapname)) {
2395
gf_msg_debug(THIS->name, 0,
2398
snap->snapname, uuid_utoa(snap->snap_id));
2408
glusterd_find_snap_by_id(uuid_t snap_id)
2410
glusterd_snap_t *snap = NULL;
2411
glusterd_conf_t *priv = NULL;
2413
priv = THIS->private;
2416
if (gf_uuid_is_null(snap_id))
2419
cds_list_for_each_entry(snap, &priv->snapshots, snap_list)
2421
if (!gf_uuid_compare(snap->snap_id, snap_id)) {
2422
gf_msg_debug(THIS->name, 0,
2425
snap->snapname, uuid_utoa(snap->snap_id));
2435
glusterd_snapshot_umount(glusterd_volinfo_t *snap_vol,
2436
glusterd_brickinfo_t *brickinfo, int32_t brick_count)
2439
int retry_count = 0;
2440
glusterd_conf_t *priv = NULL;
2441
char pidfile[PATH_MAX] = {
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;
2453
priv = this->private;
2456
GF_ASSERT(brickinfo);
2457
GF_ASSERT(snap_vol);
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;
2466
/* Check if the brick is mounted and then try unmounting the brick */
2467
ret = glusterd_get_brick_root(brickinfo->path, &mnt_pt);
2469
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICK_PATH_UNMOUNTED,
2471
"of the brick %s for volume %s (snap %s)"
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 */
2478
unmount = _gf_false;
2481
glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
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)) {
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);
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);
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.
2503
* TBD: figure out where that garbage is coming from
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));
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.
2517
* TBD: figure out a real solution
2526
glusterd_snapshot_remove(dict_t *rsp_dict, glusterd_volinfo_t *snap_vol,
2527
glusterd_brickinfo_t *brickinfo, int32_t brick_count)
2530
xlator_t *this = NULL;
2531
struct stat stbuf = {
2534
struct glusterd_snap_ops *snap_ops = NULL;
2535
char snap_path[4352] = "";
2539
GF_ASSERT(snap_vol);
2540
GF_ASSERT(brickinfo);
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.");
2550
/* As deactivated snapshot have no active mount point we
2551
* check only for activated snapshot.
2553
if (snap_vol->status == GLUSTERD_STATUS_STARTED) {
2554
ret = sys_lstat(brickinfo->path, &stbuf);
2556
gf_msg_debug(this->name, 0, "Brick %s:%s already deleted.",
2557
brickinfo->hostname, brickinfo->path);
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 "
2568
brickinfo->hostname, brickinfo->path,
2569
snap_vol->snapshot->snapname);
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);
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 "
2582
brickinfo->hostname, brickinfo->path);
2589
ret = glusterd_snapshot_umount(snap_vol, brickinfo, brick_count);
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);
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);
2603
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
2605
"remove the snapshot %s (%s)",
2606
brickinfo->path, snap_vol->snapshot->snapname);
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);
2614
/* Do not fail the Snapshot delete since
2615
this is a cleanup operation. */
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,
2622
"%s directory : error : %s",
2623
snap_path, strerror(errno));
2625
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
2627
"%s directory : error : %s",
2628
snap_path, strerror(errno));
2631
snprintf(snap_path, sizeof(snap_path), "%s/%s", snap_mount_dir,
2632
snap_vol->snapshot->snapname);
2633
ret = sys_rmdir(snap_path);
2635
/* Do not fail the Snapshot delete since
2636
this is a cleanup operation. */
2638
if (errno == ENOENT || errno == ENOTEMPTY)
2639
gf_msg_debug(this->name, 0,
2641
"%s directory : error : %s",
2642
snap_path, strerror(errno));
2644
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
2646
"%s directory : error : %s",
2647
snap_path, strerror(errno));
2650
gf_msg_trace(this->name, 0, "Returning %d", ret);
2655
glusterd_snap_volume_remove(dict_t *rsp_dict, glusterd_volinfo_t *snap_vol,
2656
gf_boolean_t remove_snapshot, gf_boolean_t force)
2660
glusterd_brickinfo_t *brickinfo = NULL;
2661
glusterd_volinfo_t *origin_vol = NULL;
2662
xlator_t *this = THIS;
2663
int32_t brick_count = -1;
2665
GF_ASSERT(rsp_dict);
2666
GF_ASSERT(snap_vol);
2669
gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
2670
"snap_vol in NULL");
2675
cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
2678
if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
2681
ret = glusterd_brick_stop(snap_vol, brickinfo, _gf_false);
2683
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICK_STOP_FAIL,
2685
"brick for volume %s",
2689
/* Don't clean up the snap on error when
2690
force flag is disabled */
2695
/* Only remove the backend snapshot when required */
2696
if (remove_snapshot) {
2697
ret = glusterd_snapshot_remove(rsp_dict, snap_vol, brickinfo,
2700
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2702
"snapshot volume %s",
2711
ret = glusterd_store_delete_volume(snap_vol);
2713
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOL_DELETE_FAIL,
2714
"Failed to remove volume %s "
2722
if (!cds_list_empty(&snap_vol->snapvol_list)) {
2723
ret = glusterd_volinfo_find(snap_vol->parent_volname, &origin_vol);
2725
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
2727
"parent volinfo %s for volume %s",
2728
snap_vol->parent_volname, snap_vol->volname);
2733
origin_vol->snap_count--;
2736
glusterd_volinfo_unref(snap_vol);
2741
gf_msg_trace(this->name, 0, "returning %d", ret);
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)
2752
glusterd_volinfo_t *snap_vol = NULL;
2753
glusterd_volinfo_t *tmp = NULL;
2754
xlator_t *this = THIS;
2756
GF_ASSERT(rsp_dict);
2760
gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
2766
cds_list_for_each_entry_safe(snap_vol, tmp, &snap->volumes, vol_list)
2768
ret = glusterd_snap_volume_remove(rsp_dict, snap_vol, remove_snapshot,
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,
2775
"volinfo %s for snap %s",
2776
snap_vol->volname, snap->snapname);
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 *
2786
ret = glusterd_store_delete_snap(snap);
2788
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2789
"Failed to remove snap %s from store", snap->snapname);
2796
ret = glusterd_snapobject_delete(snap);
2798
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
2806
gf_msg_trace(THIS->name, 0, "returning %d", ret);
2811
glusterd_snapshot_get_snapvol_detail(dict_t *dict, glusterd_volinfo_t *snap_vol,
2812
const char *keyprefix, const int detail)
2816
char key[64] = ""; /* keyprefix is quite small, up to 32 byts */
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;
2824
conf = this->private;
2828
GF_ASSERT(snap_vol);
2829
GF_ASSERT(keyprefix);
2832
value = gf_strdup(snap_vol->volname);
2836
keylen = snprintf(key, sizeof(key), "%s.volname", keyprefix);
2837
ret = dict_set_dynstrn(dict, key, keylen, value);
2839
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2841
"volume name in dictionary: %s",
2847
value = gf_strdup(uuid_utoa(snap_vol->volume_id));
2848
if (NULL == value) {
2853
keylen = snprintf(key, sizeof(key), "%s.vol-id", keyprefix);
2854
ret = dict_set_dynstrn(dict, key, keylen, value);
2856
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_MEMORY,
2858
"volume id in dictionary: %s",
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"));
2870
case GLUSTERD_STATUS_STOPPED:
2871
ret = dict_set_nstrn(dict, key, keylen, "Stopped", SLEN("Stopped"));
2873
case GD_SNAP_STATUS_NONE:
2874
ret = dict_set_nstrn(dict, key, keylen, "None", SLEN("None"));
2877
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
2878
"Invalid volume status");
2883
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2884
"Failed to set volume status"
2885
" in dictionary: %s",
2890
ret = glusterd_volinfo_find(snap_vol->parent_volname, &origin_vol);
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",
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.
2903
ret = dict_get_uint64(conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
2907
gf_msg_debug(this->name, 0,
2908
"%s is not present in "
2910
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
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",
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",
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);
2934
ret = dict_set_int32(dict, key, 0);
2936
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2937
"Failed to set available snaps");
2941
keylen = snprintf(key, sizeof(key), "%s.snapcount", keyprefix);
2942
ret = dict_set_int32n(dict, key, keylen, origin_vol->snap_count);
2944
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
2945
"Could not save snapcount");
2952
/* Parent volume name */
2953
value = gf_strdup(snap_vol->parent_volname);
2957
keylen = snprintf(key, sizeof(key), "%s.origin-volname", keyprefix);
2958
ret = dict_set_dynstrn(dict, key, keylen, value);
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",
2977
glusterd_snapshot_get_snap_detail(dict_t *dict, glusterd_snap_t *snap,
2978
const char *keyprefix,
2979
glusterd_volinfo_t *volinfo)
2983
char key[32] = ""; /* keyprefix is quite small, up to 16 bytes */
2985
char timestr[GF_TIMESTR_SIZE] = "";
2987
glusterd_volinfo_t *snap_vol = NULL;
2988
glusterd_volinfo_t *tmp_vol = NULL;
2989
xlator_t *this = THIS;
2993
GF_ASSERT(keyprefix);
2996
value = gf_strdup(snap->snapname);
3000
keylen = snprintf(key, sizeof(key), "%s.snapname", keyprefix);
3001
ret = dict_set_dynstrn(dict, key, keylen, value);
3003
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3005
"snap name in dictionary");
3010
value = gf_strdup(uuid_utoa(snap->snap_id));
3011
if (NULL == value) {
3016
keylen = snprintf(key, sizeof(key), "%s.snap-id", keyprefix);
3017
ret = dict_set_dynstrn(dict, key, keylen, value);
3019
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3021
"snap id in dictionary");
3026
gf_time_fmt_FT(timestr, sizeof timestr, snap->time_stamp);
3027
value = gf_strdup(timestr);
3029
if (NULL == value) {
3034
keylen = snprintf(key, sizeof(key), "%s.snap-time", keyprefix);
3035
ret = dict_set_dynstrn(dict, key, keylen, value);
3037
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3039
"snap time stamp in dictionary");
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) {
3052
keylen = snprintf(key, sizeof(key), "%s.snap-desc", keyprefix);
3053
ret = dict_set_dynstrn(dict, key, keylen, value);
3055
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3057
"snap description in dictionary");
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"));
3068
case GD_SNAP_STATUS_IN_USE:
3069
ret = dict_set_nstrn(dict, key, keylen, "In-use", SLEN("In-use"));
3071
case GD_SNAP_STATUS_DECOMMISSION:
3072
ret = dict_set_nstrn(dict, key, keylen, "Decommisioned",
3073
SLEN("Decommisioned"));
3075
case GD_SNAP_STATUS_RESTORED:
3076
ret = dict_set_nstrn(dict, key, keylen, "Restored",
3079
case GD_SNAP_STATUS_NONE:
3080
ret = dict_set_nstrn(dict, key, keylen, "None", SLEN("None"));
3083
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
3084
"Invalid snap status");
3089
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3090
"Failed to set snap status "
3097
snprintf(key, sizeof(key), "%s.vol%d", keyprefix, volcount);
3098
ret = glusterd_snapshot_get_snapvol_detail(dict, volinfo, key, 0);
3100
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_DICT_GET_FAILED,
3102
"get volume detail %s for snap %s",
3103
snap_vol->volname, snap->snapname);
3109
cds_list_for_each_entry_safe(snap_vol, tmp_vol, &snap->volumes, vol_list)
3112
snprintf(key, sizeof(key), "%s.vol%d", keyprefix, volcount);
3113
ret = glusterd_snapshot_get_snapvol_detail(dict, snap_vol, key, 1);
3115
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3117
"get volume detail %s for snap %s",
3118
snap_vol->volname, snap->snapname);
3124
keylen = snprintf(key, sizeof(key), "%s.vol-count", keyprefix);
3125
ret = dict_set_int32n(dict, key, keylen, volcount);
3127
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3128
"Failed to set %s", key);
3141
glusterd_snapshot_get_all_snap_info(dict_t *dict)
3146
glusterd_snap_t *snap = NULL;
3147
glusterd_snap_t *tmp_snap = NULL;
3148
glusterd_conf_t *priv = NULL;
3149
xlator_t *this = THIS;
3151
priv = this->private;
3154
/* General parameter validation */
3157
cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
3160
snprintf(key, sizeof(key), "snap%d", snapcount);
3161
ret = glusterd_snapshot_get_snap_detail(dict, snap, key, NULL);
3163
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3165
"snapdetail for snap %s",
3171
ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3173
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3174
"Failed to set snapcount");
3184
glusterd_snapshot_get_info_by_volume(dict_t *dict, char *volname, char *err_str,
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;
3199
conf = this->private;
3205
ret = glusterd_volinfo_find(volname, &volinfo);
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",
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.
3217
ret = dict_get_uint64(conf->opts, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT,
3221
gf_msg_debug(this->name, 0,
3222
"%s is not present in "
3224
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
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",
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",
3243
if (snap_limit > volinfo->snap_count)
3244
ret = dict_set_int32_sizen(dict, "snaps-available",
3245
snap_limit - volinfo->snap_count);
3247
ret = dict_set_int32_sizen(dict, "snaps-available", 0);
3249
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3250
"Failed to set available snaps");
3254
/* Origin volume name */
3255
value = gf_strdup(volinfo->volname);
3259
ret = dict_set_dynstr_sizen(dict, "origin-volname", value);
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",
3269
cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
3273
snprintf(key, sizeof(key), "snap%d", snapcount);
3274
ret = glusterd_snapshot_get_snap_detail(dict, snap_vol->snapshot, key,
3277
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3279
"snapdetail for snap %s",
3280
snap_vol->snapshot->snapname);
3284
ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3286
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3287
"Failed to set snapcount");
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.
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
3310
glusterd_handle_snapshot_info(rpcsvc_request_t *req, glusterd_op_t op,
3311
dict_t *dict, char *err_str, size_t len)
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;
3321
GF_VALIDATE_OR_GOTO(this->name, req, out);
3322
GF_VALIDATE_OR_GOTO(this->name, dict, out);
3324
ret = dict_get_int32(dict, "sub-cmd", &cmd);
3326
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3327
"Failed to get type "
3328
"of snapshot info");
3333
case GF_SNAP_INFO_TYPE_ALL: {
3334
ret = glusterd_snapshot_get_all_snap_info(dict);
3336
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3337
"Failed to get info of all snaps");
3343
case GF_SNAP_INFO_TYPE_SNAP: {
3344
ret = dict_get_str(dict, "snapname", &snapname);
3346
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3347
"Failed to get snap name");
3351
ret = dict_set_int32_sizen(dict, "snapcount", 1);
3353
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3354
"Failed to set snapcount");
3358
snap = glusterd_find_snap_by_name(snapname);
3360
snprintf(err_str, len, "Snapshot (%s) does not exist",
3362
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
3367
ret = glusterd_snapshot_get_snap_detail(dict, snap, "snap1", NULL);
3369
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
3370
"Failed to get snap detail of snap "
3378
case GF_SNAP_INFO_TYPE_VOL: {
3379
ret = dict_get_str(dict, "volname", &volname);
3381
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
3382
"Failed to get volname");
3385
ret = glusterd_snapshot_get_info_by_volume(dict, volname, err_str,
3388
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
3389
"Failed to get volume info of volume "
3399
ret = dict_set_int8(dict, "snap-driven", snap_driven);
3401
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3402
"Failed to set snap-driven");
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
3409
ret = glusterd_op_send_cli_response(op, 0, 0, req, dict, err_str);
3411
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
3412
"Failed to send cli "
3423
/* This function sets all the snapshot names in the dictionary */
3425
glusterd_snapshot_get_all_snapnames(dict_t *dict)
3429
char *snapname = NULL;
3432
glusterd_snap_t *snap = NULL;
3433
glusterd_snap_t *tmp_snap = NULL;
3434
glusterd_conf_t *priv = NULL;
3435
xlator_t *this = THIS;
3437
priv = this->private;
3441
cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
3444
snapname = gf_strdup(snap->snapname);
3446
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3451
keylen = snprintf(key, sizeof(key), "snapname%d", snapcount);
3452
ret = dict_set_dynstrn(dict, key, keylen, snapname);
3455
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3456
"Failed to set %s", key);
3461
ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3463
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3464
"Failed to set snapcount");
3474
/* This function sets all the snapshot names
3475
under a given volume in the dictionary */
3477
glusterd_snapshot_get_vol_snapnames(dict_t *dict, glusterd_volinfo_t *volinfo)
3481
char *snapname = NULL;
3483
glusterd_volinfo_t *snap_vol = NULL;
3484
glusterd_volinfo_t *tmp_vol = NULL;
3485
xlator_t *this = THIS;
3490
cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
3494
snprintf(key, sizeof(key), "snapname%d", snapcount);
3496
ret = dict_set_dynstr_with_alloc(dict, key,
3497
snap_vol->snapshot->snapname);
3499
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3508
ret = dict_set_int32_sizen(dict, "snapcount", snapcount);
3510
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3511
"Failed to set snapcount");
3522
glusterd_handle_snapshot_list(rpcsvc_request_t *req, glusterd_op_t op,
3523
dict_t *dict, char *err_str, size_t len,
3527
char *volname = NULL;
3528
glusterd_volinfo_t *volinfo = NULL;
3529
xlator_t *this = THIS;
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);
3535
/* Ignore error for getting volname as it is optional */
3536
ret = dict_get_str(dict, "volname", &volname);
3538
if (NULL == volname) {
3539
ret = glusterd_snapshot_get_all_snapnames(dict);
3541
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_LIST_GET_FAIL,
3542
"Failed to get snapshot list");
3546
ret = glusterd_volinfo_find(volname, &volinfo);
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",
3551
*op_errno = EG_NOVOL;
3555
ret = glusterd_snapshot_get_vol_snapnames(dict, volinfo);
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);
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);
3567
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
3568
"Failed to send cli "
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
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
3590
* @return Negative value on Failure and 0 in success
3593
glusterd_handle_snapshot_create(rpcsvc_request_t *req, glusterd_op_t op,
3594
dict_t *dict, char *err_str, size_t len)
3597
char *volname = NULL;
3598
char *snapname = NULL;
3599
int64_t volcount = 0;
3600
xlator_t *this = THIS;
3603
char *username = NULL;
3604
char *password = NULL;
3605
uuid_t *uuid_ptr = NULL;
3606
uuid_t tmp_uuid = {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] = "";
3617
ret = dict_get_int64(dict, "volcount", &volcount);
3619
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3621
"get the volume count");
3624
if (volcount <= 0) {
3625
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
3626
"Invalid volume count %" PRId64 " supplied", volcount);
3631
ret = dict_get_str(dict, "snapname", &snapname);
3633
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3634
"failed to get the snapname");
3638
timestamp = dict_get_str_boolean(dict, "no-timestamp", _gf_false);
3639
if (timestamp == -1) {
3640
gf_log(this->name, GF_LOG_ERROR,
3642
"no-timestamp flag ");
3646
snap_time = gf_time();
3647
ret = dict_set_int64(dict, "snap-time", (int64_t)snap_time);
3649
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3650
"Unable to set snap-time");
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,
3659
ret = dict_set_dynstr_with_alloc(dict, "snapname", new_snapname);
3661
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3666
snapname = new_snapname;
3669
if (strlen(snapname) >= GLUSTERD_MAX_SNAP_NAME) {
3670
snprintf(err_str, len,
3671
"snapname cannot exceed 255 "
3673
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s",
3679
uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3681
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3687
gf_uuid_generate(*uuid_ptr);
3688
ret = dict_set_bin(dict, "snap-id", uuid_ptr, sizeof(uuid_t));
3690
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3691
"Unable to set snap-id");
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);
3701
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3702
"Failed to get volume name");
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);
3712
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3713
"Failed to set snap "
3714
"username for volume %s",
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);
3725
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3726
"Failed to set snap "
3727
"password for volume %s",
3733
uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3735
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
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));
3745
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3746
"Unable to set snap_volid");
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);
3754
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3755
"Unable to set snap volname");
3761
ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
3763
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
3764
"Failed to initiate snap "
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
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
3783
* return : 0 in case of success.
3784
* -1 in case of failure.
3788
glusterd_handle_snapshot_status(rpcsvc_request_t *req, glusterd_op_t op,
3789
dict_t *dict, char *err_str, size_t len)
3797
ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
3799
gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
3800
"Failed to initiate "
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
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
3820
* @return Negative value on Failure and 0 in success
3823
glusterd_handle_snapshot_clone(rpcsvc_request_t *req, glusterd_op_t op,
3824
dict_t *dict, char *err_str, size_t len)
3827
char *clonename = NULL;
3828
char *snapname = NULL;
3829
xlator_t *this = THIS;
3832
char *username = NULL;
3833
char *password = NULL;
3834
char *volname = NULL;
3835
uuid_t *uuid_ptr = NULL;
3836
uuid_t tmp_uuid = {0};
3838
char snap_volname[GD_VOLUME_NAME_MAX] = "";
3844
ret = dict_get_str(dict, "clonename", &clonename);
3846
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3848
"get the clone name");
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);
3856
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3857
"Failed to set clone "
3858
"name for volume locking");
3863
ret = dict_get_str(dict, "snapname", &snapname);
3865
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3866
"failed to get the snapname");
3870
uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3872
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3878
gf_uuid_generate(*uuid_ptr);
3879
ret = dict_set_bin(dict, "clone-id", uuid_ptr, sizeof(uuid_t));
3881
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3882
"Unable to set clone-id");
3888
ret = dict_get_str(dict, "snapname", &snapname);
3890
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3891
"Failed to get snapname name");
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);
3900
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3901
"Failed to set clone "
3902
"username for volume %s",
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);
3913
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3914
"Failed to set clone "
3915
"password for volume %s",
3921
uuid_ptr = GF_MALLOC(sizeof(uuid_t), gf_common_mt_uuid_t);
3923
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
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));
3933
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3934
"Unable to set clone_volid");
3938
snprintf(key, sizeof(key), "clone-volname%d", i);
3939
ret = dict_set_dynstr_with_alloc(dict, key, snap_volname);
3941
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3942
"Unable to set snap volname");
3947
ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
3949
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
3950
"Failed to initiate "
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
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
3968
* @return Negative value on Failure and 0 in success
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)
3976
char *snapname = 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;
3986
conf = this->private;
3993
ret = dict_get_str(dict, "snapname", &snapname);
3995
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4001
snap = glusterd_find_snap_by_name(snapname);
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",
4011
list_for_each_entry(snap_volinfo, &snap->volumes, vol_list)
4014
keylen = snprintf(key, sizeof(key), "volname%d", i);
4015
buf = gf_strdup(snap_volinfo->parent_volname);
4020
ret = dict_set_dynstrn(dict, key, keylen, buf);
4022
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4024
"parent volume name %s in the dict",
4025
snap_volinfo->parent_volname);
4032
ret = dict_set_int32_sizen(dict, "volcount", i);
4034
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4035
"Could not save volume count");
4039
ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
4041
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
4042
"Failed to initiate snap phases");
4053
glusterd_create_snap_object(dict_t *dict, dict_t *rsp_dict)
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;
4062
int64_t time_stamp = 0;
4064
priv = this->private;
4067
GF_ASSERT(rsp_dict);
4069
/* Fetch snapname, description, id and time from dict */
4070
ret = dict_get_str(dict, "snapname", &snapname);
4072
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4073
"Unable to fetch snapname");
4077
/* Ignore ret value for description */
4078
ret = dict_get_str(dict, "description", &description);
4080
ret = dict_get_bin(dict, "snap-id", (void **)&snap_id);
4082
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4083
"Unable to fetch snap_id");
4087
ret = dict_get_int64(dict, "snap-time", &time_stamp);
4089
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4090
"Unable to fetch snap-time");
4093
if (time_stamp <= 0) {
4095
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
4096
"Invalid time-stamp: %" PRId64, time_stamp);
4100
cds_list_for_each_entry(snap, &priv->snapshots, snap_list)
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));
4116
snap = glusterd_new_snap_object();
4118
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
4120
"the snap object for snap %s",
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.
4133
snap->snap_status = GD_SNAP_STATUS_INIT;
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");
4144
ret = glusterd_store_snap(snap);
4146
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
4147
"Could not store snap"
4153
glusterd_list_add_order(&snap->snap_list, &priv->snapshots,
4154
glusterd_compare_snap_time);
4156
gf_msg_trace(this->name, 0, "Snapshot %s added to the list",
4164
glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_false);
4171
/* Added missed_snap_entry to rsp_dict */
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)
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;
4183
xlator_t *this = THIS;
4186
GF_ASSERT(rsp_dict);
4187
GF_ASSERT(snap_vol);
4188
GF_ASSERT(brickinfo);
4190
snap_uuid = gf_strdup(uuid_utoa(snap_vol->snapshot->snap_id));
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);
4205
/* Fetch the missed_snap_count from the dict */
4206
ret = dict_get_int32(rsp_dict, "missed_snap_count", &missed_snap_count);
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;
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);
4218
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4219
"Failed to set missed_snap_entry (%s) "
4224
missed_snap_count++;
4226
/* Setting the new missed_snap_count in the dict */
4227
ret = dict_set_int32_sizen(rsp_dict, "missed_snap_count",
4230
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4231
"Failed to set missed_snap_count for %s "
4241
gf_msg_trace(this->name, 0, "Returning %d", ret);
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)
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 = {
4258
GF_ASSERT(snap_volinfo);
4259
GF_ASSERT(brickinfo);
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.
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);
4273
ret = snap_ops->activate(brickinfo, snap_volinfo->snapshot->snapname,
4274
snap_volinfo->volname, brick_count);
4277
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_LVM_MOUNT_FAILED,
4278
"Failed to activate snapshot.");
4282
ret = sys_stat(brickinfo->path, &statbuf);
4284
gf_msg(this->name, GF_LOG_WARNING, errno, GD_MSG_FILE_OP_FAILED,
4285
"stat of the brick %s "
4287
brickinfo->path, strerror(errno));
4292
ret = sys_lsetxattr(brickinfo->path, GF_XATTR_VOL_ID_KEY,
4293
snap_volinfo->volume_id, 16, XATTR_REPLACE);
4295
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_SET_XATTR_FAIL,
4297
"extended attribute %s on %s. Reason: "
4299
GF_XATTR_VOL_ID_KEY, brickinfo->path, strerror(errno),
4300
snap_volinfo->volname);
4306
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_UMOUNTING_SNAP_BRICK,
4307
"unmounting the snap brick"
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);
4315
gf_msg_trace(this->name, 0, "Returning %d", ret);
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)
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;
4334
xlator_t *this = THIS;
4335
char abspath[PATH_MAX] = "";
4338
GF_ASSERT(rsp_dict);
4339
GF_ASSERT(snap_vol);
4340
GF_ASSERT(original_brickinfo);
4342
snprintf(key, sizeof(key), "vol%" PRId64 ".origin_path%d", volcount,
4345
ret = dict_set_dynstr_with_alloc(dict, key,
4346
original_brickinfo->origin_path);
4348
ret = dict_set_dynstr_with_alloc(dict, key, original_brickinfo->path);
4351
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4352
"Failed to set %s", key);
4356
ret = glusterd_brickinfo_new(&snap_brickinfo);
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);
4365
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".fstype%d", volcount,
4367
ret = dict_get_strn(dict, key, keylen, &value);
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));
4375
if (is_origin_glusterd(dict) == _gf_true)
4376
add_missed_snap = _gf_true;
4379
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%d", volcount,
4381
ret = dict_get_strn(dict, key, keylen, &value);
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));
4389
if (is_origin_glusterd(dict) == _gf_true)
4390
add_missed_snap = _gf_true;
4393
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".origin_path%d",
4394
volcount, brick_count);
4395
ret = dict_get_strn(dict, key, keylen, &value);
4397
/* Update the origin_path to snap_brickinfo */
4398
gf_strncpy(snap_brickinfo->origin_path, value,
4399
sizeof(snap_brickinfo->origin_path));
4401
if (is_origin_glusterd(dict) == _gf_true)
4402
add_missed_snap = _gf_true;
4405
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_type%d", volcount,
4407
ret = dict_get_strn(dict, key, keylen, &value);
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));
4415
if (is_origin_glusterd(dict) == _gf_true)
4416
add_missed_snap = _gf_true;
4419
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".mnt_opts%d", volcount,
4421
ret = dict_get_strn(dict, key, keylen, &value);
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));
4429
if (is_origin_glusterd(dict) == _gf_true)
4430
add_missed_snap = _gf_true;
4433
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".brickdir%d", volcount,
4435
ret = dict_get_strn(dict, key, keylen, &snap_brick_dir);
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
4441
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_NOT_FOUND,
4443
"snap mount path(%s). Adding to missed_snap_list",
4445
snap_brickinfo->snap_status = -1;
4447
snap_brick_dir = original_brickinfo->mount_dir;
4449
/* In origiator node add snaps missed
4450
* from different nodes to the dict
4452
if (is_origin_glusterd(dict) == _gf_true)
4453
add_missed_snap = _gf_true;
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);
4466
snap_brickinfo->snap_status = -1;
4467
add_missed_snap = _gf_true;
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);
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);
4483
/* Create brick-path in the format /var/run/gluster/snaps/ *
4484
* <snap-uuid>/<original-brick#>/snap-brick-dir *
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,
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);
4501
ret = gf_canonicalize_path(snap_brickinfo->path);
4503
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_CANONICALIZE_FAIL,
4504
"Failed to canonicalize path");
4508
gf_strncpy(snap_brickinfo->hostname, original_brickinfo->hostname,
4509
sizeof(snap_brickinfo->hostname));
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,
4518
"failed for brick %s. The underlying filesystem"
4519
" may be in bad state",
4520
snap_brickinfo->path);
4525
gf_strncpy(snap_brickinfo->real_path, abspath,
4526
sizeof(snap_brickinfo->real_path));
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);
4536
GLUSTERD_ASSIGN_BRICKID_TO_BRICKINFO(snap_brickinfo, snap_vol,
4539
gf_strncpy(snap_brickinfo->brick_id, original_brickinfo->brick_id,
4540
sizeof(snap_brickinfo->brick_id));
4543
if (ret && snap_brickinfo)
4544
GF_FREE(snap_brickinfo);
4546
gf_msg_trace(this->name, 0, "Returning %d", ret);
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)
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;
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;
4568
priv = this->private;
4570
GF_ASSERT(snap_vol);
4571
GF_ASSERT(brickinfo);
4575
keylen = snprintf(key, sizeof(key), "vol%d.origin_path%d", volcount,
4577
ret = dict_get_strn(dict, key, keylen, &origin_path);
4579
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4585
gf_strncpy(brickinfo->origin_path, origin_path,
4586
sizeof(brickinfo->origin_path));
4589
GLUSTERD_GET_UUID_NOHYPHEN(snap_volume_id, snap_vol->volume_id);
4592
ret = dict_get_ptr(dict, "parent_snap_volume_id",
4593
(void **)&origin_snap_volume_id);
4595
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4597
"parent_snap_volume_id");
4600
ret = dict_get_ptr(dict, "parent_snapname", (void **)&origin_snapname);
4602
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4607
glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
4609
ret = snap_ops->clone(brickinfo, origin_snapname, origin_snap_volume_id,
4610
snap_vol->volname, snap_volume_id, brick_count);
4612
keylen = snprintf(key, sizeof(key), "vol%d.snap_plugin", volcount);
4613
ret = dict_get_strn(dict, key, keylen, &snap_plugin);
4615
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
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);
4628
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
4629
"Failed to take snapshot of "
4631
brickinfo->hostname, origin_path);
4635
/* create the complete brick here in case of clone and
4636
* activate-on-create configuration.
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,
4644
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_CREATION_FAIL,
4646
"create the brick for the snap %s, volume %s",
4647
snap_vol->snapshot->snapname, snap_vol->volname);
4653
gf_msg_trace(this->name, 0, "Returning %d", ret);
4658
glusterd_snap_clear_unsupported_opt(
4659
glusterd_volinfo_t *volinfo,
4660
struct gd_snap_unsupported_opt_t *unsupported_opt)
4665
GF_VALIDATE_OR_GOTO("glusterd", volinfo, out);
4667
for (i = 0; unsupported_opt[i].key; i++) {
4668
glusterd_volinfo_get(volinfo, unsupported_opt[i].key,
4669
&unsupported_opt[i].value);
4671
if (unsupported_opt[i].value) {
4672
unsupported_opt[i].value = gf_strdup(unsupported_opt[i].value);
4673
if (!unsupported_opt[i].value) {
4677
dict_del(volinfo->dict, unsupported_opt[i].key);
4687
glusterd_snap_set_unsupported_opt(
4688
glusterd_volinfo_t *volinfo,
4689
struct gd_snap_unsupported_opt_t *unsupported_opt)
4694
GF_VALIDATE_OR_GOTO("glusterd", volinfo, out);
4696
for (i = 0; unsupported_opt[i].key; i++) {
4697
if (!unsupported_opt[i].value)
4700
ret = dict_set_dynstr(volinfo->dict, unsupported_opt[i].key,
4701
unsupported_opt[i].value);
4703
gf_msg("glusterd", GF_LOG_ERROR, -ret, GD_MSG_DICT_SET_FAILED,
4707
unsupported_opt[i].value = NULL;
4715
/* This function will create a new volinfo and then
4716
* dup the entries from volinfo to the new_volinfo.
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
4722
* @return 0 on success else -1
4725
glusterd_volinfo_dup(glusterd_volinfo_t *volinfo,
4726
glusterd_volinfo_t **dup_volinfo,
4727
gf_boolean_t set_userauth)
4730
xlator_t *this = THIS;
4731
glusterd_volinfo_t *new_volinfo = NULL;
4733
GF_VALIDATE_OR_GOTO(this->name, volinfo, out);
4734
GF_VALIDATE_OR_GOTO(this->name, dup_volinfo, out);
4736
ret = glusterd_volinfo_new(&new_volinfo);
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",
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);
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);
4768
glusterd_auth_set_username(new_volinfo, volinfo->auth.username);
4769
glusterd_auth_set_password(new_volinfo, volinfo->auth.password);
4772
*dup_volinfo = new_volinfo;
4775
if (ret && (NULL != new_volinfo)) {
4776
(void)glusterd_volinfo_unref(new_volinfo);
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,
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;
4795
int32_t brick_count = 0;
4796
xlator_t *this = THIS;
4797
char *clonename = NULL;
4798
gf_boolean_t conf_present = _gf_false;
4800
struct glusterd_snap_ops *snap_ops = NULL;
4801
char *snap_plugin = NULL;
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}};
4810
priv = this->private;
4813
GF_ASSERT(origin_vol);
4814
GF_ASSERT(rsp_dict);
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);
4820
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4821
"Failed to get %s for "
4823
key, snap->snapname);
4826
keylen = snprintf(key, sizeof(key), "volume%" PRId64 "_password", volcount);
4827
ret = dict_get_strn(dict, key, keylen, &password);
4829
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4830
"Failed to get %s for "
4832
key, snap->snapname);
4836
snprintf(key, sizeof(key), "vol%" PRId64 "_volid", volcount);
4837
ret = dict_get_bin(dict, key, (void **)&snap_volid);
4839
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4840
"Unable to fetch snap_volid");
4844
/* We are not setting the username and password here as
4845
* we need to set the user name and password passed in
4848
ret = glusterd_volinfo_dup(origin_vol, &snap_vol, _gf_false);
4850
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
4851
"Failed to duplicate volinfo "
4852
"for the snapshot %s",
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;
4864
snap_vol->is_snap_volume = _gf_false;
4865
ret = dict_get_str(dict, "clonename", &clonename);
4867
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4870
key, snap->snapname);
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);
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);
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",
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/
4894
ret = glusterd_copy_geo_rep_files(origin_vol, snap_vol, rsp_dict);
4896
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
4898
"geo-rep config and status files for volume %s",
4899
origin_vol->volname);
4904
glusterd_auth_set_username(snap_vol, username);
4905
glusterd_auth_set_password(snap_vol, password);
4907
/* Adding snap brickinfos to the snap volinfo */
4910
/* During create, Snapshot plugin name is not set to */
4911
/* snap_vol->snap_plugin. It is available in rest of the calls */
4913
keylen = snprintf(key, sizeof(key), "vol%" PRId64 ".snap_plugin",
4915
ret = dict_get_strn(dict, key, keylen, &snap_plugin);
4917
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
4922
gf_strncpy(snap_vol->snap_plugin, snap_plugin,
4923
sizeof(snap_vol->snap_plugin));
4925
/* To use generic functions from the plugin */
4926
glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
4928
cds_list_for_each_entry(brickinfo, &origin_vol->bricks, brick_list)
4930
ret = glusterd_add_brick_to_snap_volume(dict, rsp_dict, snap_vol,
4931
brickinfo, volcount,
4932
brick_count, clone, snap_ops);
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);
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.
4951
dict_del_sizen(snap_vol->dict, "features.barrier");
4952
gd_update_volume_op_versions(snap_vol);
4955
* Create the export file from the node where ganesha.enable "on"
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);
4963
gf_msg(this->name, GF_LOG_ERROR, 0,
4964
GD_MSG_EXPORT_FILE_CREATE_FAIL,
4966
"export file for NFS-Ganesha\n");
4971
ret = dict_set_dynstr_with_alloc(snap_vol->dict,
4972
"features.cache-invalidation", "on");
4973
ret = gd_ganesha_send_dbus(clonename, "on");
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",
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.
4991
ret = dict_set_dynstr(snap_vol->dict, "ganesha.enable", "off");
4996
ret = glusterd_store_volinfo(snap_vol, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
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);
5005
ret = glusterd_copy_quota_files(origin_vol, snap_vol, &conf_present);
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);
5014
if (snap_vol->is_snap_volume) {
5015
ret = glusterd_snap_clear_unsupported_opt(snap_vol, unsupported_opt);
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);
5025
ret = generate_brick_volfiles(snap_vol);
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);
5034
ret = generate_client_volfiles(snap_vol, GF_CLIENT_TRUSTED);
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);
5043
ret = generate_client_volfiles(snap_vol, GF_CLIENT_OTHER);
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);
5053
if (snap_vol->is_snap_volume) {
5054
if (glusterd_snap_set_unsupported_opt(snap_vol, unsupported_opt)) {
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);
5064
for (i = 0; unsupported_opt[i].key; i++)
5065
GF_FREE(unsupported_opt[i].value);
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);
5073
gf_msg(this->name, GF_LOG_ERROR, 0,
5074
GD_MSG_EXPORT_FILE_CREATE_FAIL,
5076
"export file for NFS-Ganesha\n");
5080
ret = gd_ganesha_send_dbus(clonename, "off");
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",
5090
glusterd_snap_volume_remove(rsp_dict, snap_vol, _gf_true, _gf_true);
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
5103
glusterd_snapshot_activate_deactivate_prevalidate(dict_t *dict,
5107
gf_boolean_t is_op_activate)
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;
5119
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5121
if (!dict || !op_errstr) {
5122
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5123
"input parameters NULL");
5127
ret = dict_get_str(dict, "snapname", &snapname);
5129
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5130
"Getting the snap name "
5135
snap = glusterd_find_snap_by_name(snapname);
5137
snprintf(err_str, sizeof(err_str),
5138
"Snapshot (%s) does not "
5141
gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
5142
"Snapname=%s", snapname, NULL);
5143
*op_errno = EG_NOSNAP;
5148
/* If its activation of snap then fetch the flags */
5149
if (is_op_activate) {
5150
ret = dict_get_int32(dict, "flags", &flags);
5152
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5153
"Unable to get flags");
5158
/* TODO : As of now there is only volume in snapshot.
5159
* Change this when multiple volume snapshot is introduced
5161
snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5163
if (!snap_volinfo) {
5164
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOLINFO_GET_FAIL,
5165
"Unable to fetch snap_volinfo");
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;
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);
5191
snprintf(err_str, sizeof(err_str),
5192
"Snapshot %s is already deactivated.", snapname);
5201
if (ret && err_str[0] != '\0' && op_errstr) {
5202
gf_msg(this->name, loglevel, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
5204
*op_errstr = gf_strdup(err_str);
5211
glusterd_handle_snapshot_delete_vol(dict_t *dict, char *err_str,
5212
uint32_t *op_errno, int len)
5215
glusterd_volinfo_t *volinfo = NULL;
5216
xlator_t *this = THIS;
5217
char *volname = NULL;
5220
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5222
ret = dict_get_str(dict, "volname", &volname);
5224
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5230
ret = glusterd_volinfo_find(volname, &volinfo);
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 "
5241
ret = glusterd_snapshot_get_vol_snapnames(dict, volinfo);
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);
5254
glusterd_handle_snapshot_delete_all(dict_t *dict)
5259
glusterd_conf_t *priv = NULL;
5260
glusterd_snap_t *snap = NULL;
5261
glusterd_snap_t *tmp_snap = NULL;
5262
xlator_t *this = THIS;
5265
priv = this->private;
5270
cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
5272
/* indexing from 1 to n, to keep it uniform with other code
5276
ret = snprintf(key, sizeof(key), "snapname%d", i);
5281
ret = dict_set_dynstr_with_alloc(dict, key, snap->snapname);
5283
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5290
ret = dict_set_int32_sizen(dict, "snapcount", i);
5292
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5293
"Could not save snapcount");
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,
5310
int64_t volcount = 0;
5311
char *snapname = NULL;
5312
char *volname = NULL;
5315
glusterd_snap_t *snap = NULL;
5316
glusterd_volinfo_t *snap_vol = NULL;
5317
glusterd_volinfo_t *tmp = NULL;
5318
xlator_t *this = THIS;
5324
ret = dict_get_str(dict, "snapname", &snapname);
5326
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5327
"Failed to get snapname");
5331
snap = glusterd_find_snap_by_name(snapname);
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",
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)
5345
volname = gf_strdup(snap_vol->parent_volname);
5348
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
5353
keylen = snprintf(key, sizeof(key), "volname%" PRId64, volcount);
5354
ret = dict_set_dynstrn(dict, key, keylen, volname);
5356
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5358
"volume name in dictionary");
5364
ret = dict_set_int64(dict, "volcount", volcount);
5366
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5367
"Failed to set volcount");
5371
ret = glusterd_mgmt_v3_initiate_snap_phases(req, op, dict);
5373
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_INIT_FAIL,
5374
"Failed to initiate snap "
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
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
5395
* @return Negative value on Failure and 0 in success
5398
glusterd_handle_snapshot_delete(rpcsvc_request_t *req, glusterd_op_t op,
5399
dict_t *dict, char *err_str, uint32_t *op_errno,
5403
xlator_t *this = THIS;
5404
int32_t delete_cmd = -1;
5409
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5411
ret = dict_get_int32(dict, "sub-cmd", &delete_cmd);
5413
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
5414
"Failed to get sub-cmd");
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);
5424
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5426
"snapshot delete for type SNAP");
5431
case GF_SNAP_DELETE_TYPE_ALL:
5432
ret = glusterd_handle_snapshot_delete_all(dict);
5434
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5436
"snapshot delete for type ALL");
5441
case GF_SNAP_DELETE_TYPE_VOL:
5442
ret = glusterd_handle_snapshot_delete_vol(dict, err_str, op_errno,
5445
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5447
"snapshot delete for type VOL");
5454
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
5455
"Wrong snapshot delete type");
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);
5463
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_CLI_RESP,
5464
"Failed to send cli "
5475
glusterd_snapshot_remove_prevalidate(dict_t *dict, char **op_errstr,
5476
uint32_t *op_errno, dict_t *rsp_dict)
5479
char *snapname = NULL;
5480
xlator_t *this = THIS;
5481
glusterd_snap_t *snap = NULL;
5483
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5485
if (!dict || !op_errstr) {
5486
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5487
"input parameters NULL");
5491
ret = dict_get_str(dict, "snapname", &snapname);
5493
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5494
"Getting the snap name "
5499
snap = glusterd_find_snap_by_name(snapname);
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;
5508
ret = dict_set_dynstr_with_alloc(dict, "snapuuid",
5509
uuid_utoa(snap->snap_id));
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",
5524
glusterd_snapshot_status_prevalidate(dict_t *dict, char **op_errstr,
5525
uint32_t *op_errno, dict_t *rsp_dict)
5528
char *snapname = NULL;
5529
glusterd_conf_t *conf = NULL;
5530
xlator_t *this = THIS;
5532
glusterd_volinfo_t *volinfo = NULL;
5533
char *volname = NULL;
5535
conf = this->private;
5537
GF_ASSERT(op_errstr);
5538
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
5541
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5542
"Input dict is NULL");
5546
ret = dict_get_int32(dict, "sub-cmd", &cmd);
5548
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5549
"Could not fetch status cmd");
5554
case GF_SNAP_STATUS_TYPE_ALL: {
5557
case GF_SNAP_STATUS_TYPE_ITER:
5558
case GF_SNAP_STATUS_TYPE_SNAP: {
5559
ret = dict_get_str(dict, "snapname", &snapname);
5561
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5562
"Could not fetch snapname");
5566
if (!glusterd_find_snap_by_name(snapname)) {
5567
ret = gf_asprintf(op_errstr,
5571
*op_errno = EG_NOSNAP;
5576
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5577
"Snapshot (%s) does not exist", snapname);
5582
case GF_SNAP_STATUS_TYPE_VOL: {
5583
ret = dict_get_str(dict, "volname", &volname);
5585
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5586
"Could not fetch volname");
5590
ret = glusterd_volinfo_find(volname, &volinfo);
5592
ret = gf_asprintf(op_errstr,
5596
*op_errno = EG_NOVOL;
5601
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
5610
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
5623
glusterd_snapshot_activate_commit(dict_t *dict, char **op_errstr,
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;
5633
int brick_count = -1;
5634
struct glusterd_snap_ops *snap_ops = NULL;
5637
GF_ASSERT(rsp_dict);
5638
GF_ASSERT(op_errstr);
5640
if (!dict || !op_errstr) {
5641
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5642
"input parameters NULL");
5646
ret = dict_get_str(dict, "snapname", &snapname);
5648
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5649
"Getting the snap name "
5654
ret = dict_get_int32(dict, "flags", &flags);
5656
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5657
"Unable to get flags");
5661
snap = glusterd_find_snap_by_name(snapname);
5663
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5664
"Snapshot (%s) does not exist", snapname);
5669
/* TODO : As of now there is only volume in snapshot.
5670
* Change this when multiple volume snapshot is introduced
5672
snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5674
if (!snap_volinfo) {
5675
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
5676
"Unable to fetch snap_volinfo");
5681
glusterd_snapshot_plugin_by_name(snap_volinfo->snap_plugin, &snap_ops);
5683
/* create the complete brick here */
5684
cds_list_for_each_entry(brickinfo, &snap_volinfo->bricks, brick_list)
5687
if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
5690
ret = glusterd_snap_brick_create(snap_volinfo, brickinfo, brick_count,
5691
_gf_false, snap_ops);
5693
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_CREATION_FAIL,
5695
"create the brick for the snap %s, volume %s",
5696
snap_volinfo->snapshot->snapname, snap_volinfo->volname);
5701
ret = glusterd_start_volume(snap_volinfo, flags, _gf_true);
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);
5710
ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
5711
uuid_utoa(snap->snap_id));
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",
5726
glusterd_snapshot_deactivate_commit(dict_t *dict, char **op_errstr,
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] = "";
5737
GF_ASSERT(rsp_dict);
5738
GF_ASSERT(op_errstr);
5740
if (!dict || !op_errstr) {
5741
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5742
"input parameters NULL");
5746
ret = dict_get_str(dict, "snapname", &snapname);
5748
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5749
"Getting the snap name "
5754
snap = glusterd_find_snap_by_name(snapname);
5756
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5757
"Snapshot (%s) does not exist", snapname);
5762
/* TODO : As of now there is only volume in snapshot.
5763
* Change this when multiple volume snapshot is introduced
5765
snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5767
if (!snap_volinfo) {
5768
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
5769
"Unable to fetch snap_volinfo");
5774
ret = glusterd_stop_volume(snap_volinfo);
5776
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_DEACTIVATE_FAIL,
5777
"Failed to deactivate"
5783
ret = glusterd_snap_unmount(this, snap_volinfo);
5785
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_UMOUNT_FAIL,
5786
"Failed to unmounts for %s", snap->snapname);
5789
/*Remove /var/run/gluster/snaps/<snap-name> entry for deactivated snaps.
5790
* This entry will be created again during snap activate.
5792
snprintf(snap_path, sizeof(snap_path), "%s/%s", snap_mount_dir, snapname);
5793
ret = recursive_rmdir(snap_path);
5795
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
5797
"%s directory : error : %s",
5798
snap_path, strerror(errno));
5802
ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
5803
uuid_utoa(snap->snap_id));
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",
5818
glusterd_snapshot_remove_commit(dict_t *dict, char **op_errstr,
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;
5830
GF_ASSERT(rsp_dict);
5831
GF_ASSERT(op_errstr);
5833
priv = this->private;
5836
if (!dict || !op_errstr) {
5837
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5838
"input parameters NULL");
5842
ret = dict_get_str(dict, "snapname", &snapname);
5844
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5845
"Getting the snap name "
5850
snap = glusterd_find_snap_by_name(snapname);
5852
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5853
"Snapshot (%s) does not exist", snapname);
5858
ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
5859
uuid_utoa(snap->snap_id));
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",
5868
/* Save the snap status as GD_SNAP_STATUS_DECOMMISSION so
5869
* that if the node goes down the snap would be removed
5871
snap->snap_status = GD_SNAP_STATUS_DECOMMISSION;
5872
ret = glusterd_store_snap(snap);
5874
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJECT_STORE_FAIL,
5876
"store snap object %s",
5880
gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_OP_SUCCESS,
5881
"Successfully marked "
5882
"snap %s for decommission.",
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
5889
snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
5891
if (!snap_volinfo) {
5892
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
5893
"Unable to fetch snap_volinfo");
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);
5903
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_GET_FAIL,
5904
"Failed to find missed snap deletes");
5909
ret = glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_false, _gf_false);
5911
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
5912
"Failed to remove snap %s", snapname);
5916
dup_snapname = gf_strdup(snapname);
5917
if (!dup_snapname) {
5918
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
5924
ret = dict_set_dynstr(rsp_dict, "snapname", dup_snapname);
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);
5938
glusterd_do_snap_cleanup(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
5942
char *volname = NULL;
5943
xlator_t *this = THIS;
5944
glusterd_conf_t *conf = NULL;
5945
glusterd_snap_t *snap = NULL;
5947
conf = this->private;
5950
if (!dict || !op_errstr) {
5951
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY,
5952
"input parameters NULL");
5956
/* As of now snapshot of multiple volumes are not supported */
5957
ret = dict_get_str(dict, "volname1", &volname);
5959
gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5965
ret = dict_get_str(dict, "snapname", &name);
5967
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5969
"name failed (volume: %s)",
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.
5979
snap = glusterd_find_snap_by_name(name);
5981
gf_msg(this->name, GF_LOG_INFO, EINVAL, GD_MSG_SNAP_NOT_FOUND,
5982
"Snapshot (%s) does not exist", name);
5987
ret = glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_false);
5989
/* Ignore failure as this is a cleanup of half cooked
5991
gf_msg_debug(this->name, 0, "removing the snap %s failed", name);
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 */
6007
glusterd_snapshot_update_snaps_post_validate(dict_t *dict, char **op_errstr,
6011
int32_t missed_snap_count = -1;
6012
xlator_t *this = THIS;
6015
GF_ASSERT(rsp_dict);
6016
GF_ASSERT(op_errstr);
6018
ret = dict_get_int32(dict, "missed_snap_count", &missed_snap_count);
6020
gf_msg_debug(this->name, 0, "No missed snaps");
6025
ret = glusterd_add_missed_snaps_to_list(dict, missed_snap_count);
6027
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSEDSNAP_INFO_SET_FAIL,
6028
"Failed to add missed snaps to list");
6032
ret = glusterd_store_update_missed_snaps();
6034
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSEDSNAP_INFO_SET_FAIL,
6035
"Failed to update missed_snaps_list");
6040
gf_msg_trace(this->name, 0, "Returning %d", ret);
6045
glusterd_take_brick_snapshot_task(void *opaque)
6049
snap_create_args_t *snap_args = NULL;
6050
char *clonename = NULL;
6056
snap_args = (snap_create_args_t *)opaque;
6057
THIS = snap_args->this;
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);
6063
keylen = snprintf(key, sizeof(key), "snap-vol%d.brick%d.status",
6064
snap_args->volcount, snap_args->brickorder);
6066
keylen = snprintf(key, sizeof(key), "clone%d.brick%d.status",
6067
snap_args->volcount, snap_args->brickorder);
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);
6076
gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6078
"take backend snapshot for brick "
6080
snap_args->brickinfo->hostname, snap_args->brickinfo->path,
6081
snap_args->snap_vol->volname);
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,
6098
glusterd_take_brick_snapshot_cbk(int ret, call_frame_t *frame, void *opaque)
6100
snap_create_args_t *snap_args = NULL;
6101
struct syncargs *args = NULL;
6105
snap_args = (snap_create_args_t *)opaque;
6106
args = snap_args->args;
6112
synctask_barrier_wake(args);
6117
glusterd_schedule_brick_snapshot(dict_t *dict, dict_t *rsp_dict,
6118
glusterd_snap_t *snap)
6121
int32_t volcount = 0;
6122
int32_t brickcount = 0;
6123
int32_t brickorder = 0;
6124
int32_t taskcount = 0;
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;
6136
ret = synctask_barrier_init((&args));
6139
cds_list_for_each_entry(snap_vol, &snap->volumes, vol_list)
6144
cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
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);
6150
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6151
"Failed to set %s", key);
6155
if ((gf_uuid_compare(brickinfo->uuid, MY_UUID)) ||
6156
(brickinfo->snap_status == -1)) {
6157
if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) {
6159
keylen = snprintf(key, sizeof(key),
6160
"snap-vol%d.brick%d.status", volcount,
6162
ret = dict_set_int32n(rsp_dict, key, keylen, 0);
6164
gf_msg(this->name, GF_LOG_ERROR, 0,
6165
GD_MSG_DICT_SET_FAILED,
6166
"failed to add %s to "
6176
snap_args = GF_CALLOC(1, sizeof(*snap_args),
6177
gf_gld_mt_snap_create_args_t);
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;
6194
this->ctx->env, glusterd_take_brick_snapshot_task,
6195
glusterd_take_brick_snapshot_cbk, NULL, snap_args);
6197
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6199
"spawn task for snapshot create");
6208
snprintf(key, sizeof(key), "snap-vol%d_brickcount", volcount);
6209
ret = dict_set_int64(rsp_dict, key, brickcount);
6211
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6218
synctask_barrier_wait((&args), taskcount);
6222
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6223
"Failed to create snapshot");
6227
if (ret && taskcount)
6228
synctask_barrier_wait((&args), taskcount);
6234
glusterd_create_snap_object_for_clone(dict_t *dict, dict_t *rsp_dict)
6236
char *snapname = NULL;
6237
uuid_t *snap_id = NULL;
6238
glusterd_snap_t *snap = NULL;
6239
xlator_t *this = THIS;
6243
GF_ASSERT(rsp_dict);
6245
/* Fetch snapname, description, id and time from dict */
6246
ret = dict_get_str(dict, "clonename", &snapname);
6248
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6249
"Unable to fetch clonename");
6253
ret = dict_get_bin(dict, "clone-id", (void **)&snap_id);
6255
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6256
"Unable to fetch clone_id");
6260
snap = glusterd_new_snap_object();
6262
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJ_NEW_FAIL,
6264
"the snap object for snap %s",
6269
gf_strncpy(snap->snapname, snapname, sizeof(snap->snapname));
6270
gf_uuid_copy(snap->snap_id, *snap_id);
6283
glusterd_snapshot_clone_commit(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
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] = "";
6299
GF_ASSERT(op_errstr);
6300
GF_ASSERT(rsp_dict);
6301
priv = this->private;
6304
ret = dict_get_str(dict, "clonename", &snapname);
6306
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6307
"Unable to fetch clonename");
6310
tmp_name = gf_strdup(snapname);
6312
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
6318
ret = dict_set_dynstr(rsp_dict, "clonename", tmp_name);
6320
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6321
"Unable to set clonename in rsp_dict");
6327
ret = dict_get_str(dict, "snapname", &volname);
6329
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6330
"failed to get snap name");
6334
snap_parent = glusterd_find_snap_by_name(volname);
6336
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
6343
/* TODO : As of now there is only one volume in snapshot.
6344
* Change this when multiple volume snapshot is introduced
6346
origin_vol = cds_list_entry(snap_parent->volumes.next, glusterd_volinfo_t,
6349
gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
6350
"Failed to get snap "
6352
snap_parent->snapname);
6356
snap = glusterd_create_snap_object_for_clone(dict, rsp_dict);
6358
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJ_NEW_FAIL,
6360
"snap object %s failed",
6366
/* Update Parent Snapname and Volume Id for Clone */
6367
ret = dict_set_dynstr_with_alloc(dict, "parent_snapname",
6368
snap_parent->snapname);
6370
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6372
"parent snapname for %s",
6377
GLUSTERD_GET_UUID_NOHYPHEN(parent_snap_volume_id, origin_vol->volume_id);
6379
ret = dict_set_dynstr_with_alloc(dict, "parent_snap_volume_id",
6380
parent_snap_volume_id);
6382
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6384
"parent snapname for %s",
6389
snap_vol = glusterd_do_snap_vol(origin_vol, snap, dict, rsp_dict, 1, 1);
6392
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
6394
"snapshot of the volume %s failed",
6400
ret = dict_set_int64(rsp_dict, "volcount", volcount);
6402
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6403
"Failed to set volcount");
6407
ret = glusterd_schedule_brick_snapshot(dict, rsp_dict, snap);
6409
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_BACKEND_MAKE_FAIL,
6410
"Failed to take backend "
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));
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",
6427
glusterd_list_add_order(&snap_vol->vol_list, &priv->volumes,
6428
glusterd_compare_volume_name);
6435
glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_true);
6439
gf_msg_trace(this->name, 0, "Returning %d", ret);
6444
glusterd_snapshot_create_commit(dict_t *dict, char **op_errstr,
6445
uint32_t *op_errno, dict_t *rsp_dict)
6449
int64_t volcount = 0;
6450
int32_t snap_activate = 0;
6452
char *snapname = NULL;
6453
char *volname = NULL;
6454
char *tmp_name = NULL;
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;
6464
GF_ASSERT(op_errstr);
6465
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
6466
GF_ASSERT(rsp_dict);
6467
priv = this->private;
6470
ret = dict_get_int64(dict, "volcount", &volcount);
6472
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6474
"get the volume count");
6478
ret = dict_get_str(dict, "snapname", &snapname);
6480
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6481
"Unable to fetch snapname");
6484
tmp_name = gf_strdup(snapname);
6486
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
6492
ret = dict_set_dynstr(rsp_dict, "snapname", tmp_name);
6494
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6495
"Unable to set snapname in rsp_dict");
6501
snap = glusterd_create_snap_object(dict, rsp_dict);
6503
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6505
"snap object %s failed",
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);
6515
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6516
"failed to get volume name");
6520
ret = glusterd_volinfo_find(volname, &origin_vol);
6522
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
6523
"failed to get the volinfo for "
6529
if (is_origin_glusterd(dict)) {
6530
ret = glusterd_is_snap_soft_limit_reached(origin_vol, rsp_dict);
6532
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED,
6534
"check soft limit exceeded or not, "
6536
origin_vol->volname);
6541
snap_vol = glusterd_do_snap_vol(origin_vol, snap, dict, rsp_dict, i, 0);
6544
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
6546
"snapshot of the volume %s failed",
6551
ret = dict_set_int64(rsp_dict, "volcount", volcount);
6553
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6554
"Failed to set volcount");
6558
ret = glusterd_schedule_brick_snapshot(dict, rsp_dict, snap);
6560
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
6561
"Failed to take backend "
6567
ret = dict_set_dynstr_with_alloc(rsp_dict, "snapuuid",
6568
uuid_utoa(snap->snap_id));
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",
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)
6582
snap_vol->status = GLUSTERD_STATUS_STOPPED;
6583
ret = glusterd_store_volinfo(snap_vol,
6584
GLUSTERD_VOLINFO_VER_AC_INCREMENT);
6586
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_SET_FAIL,
6587
"Failed to store snap volinfo %s", snap_vol->volname);
6595
/* Activate created bricks in case of activate-on-create config. */
6596
ret = dict_get_int32(dict, "flags", &flags);
6598
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
6599
"Unable to get flags");
6603
cds_list_for_each_entry(snap_vol, &snap->volumes, vol_list)
6605
ret = glusterd_start_volume(snap_vol, flags, _gf_true);
6607
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
6608
"Failed to activate snap volume %s of the "
6610
snap_vol->volname, snap->snapname);
6620
glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true, _gf_false);
6624
gf_msg_trace(this->name, 0, "Returning %d", ret);
6629
snap_max_hard_limit_set_commit(dict_t *dict, uint64_t value, char *volname,
6632
char err_str[PATH_MAX] = "";
6633
glusterd_conf_t *conf = NULL;
6634
glusterd_volinfo_t *volinfo = NULL;
6636
xlator_t *this = THIS;
6637
char *next_version = NULL;
6640
GF_ASSERT(op_errstr);
6642
conf = this->private;
6646
/* TODO: Initiate auto deletion when there is a limit change */
6648
/* For system limit */
6649
ret = dict_set_uint64(conf->opts,
6650
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, value);
6652
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6654
"%s in the options",
6655
GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT);
6659
ret = glusterd_get_next_global_opt_version_str(conf->opts,
6664
ret = dict_set_str_sizen(conf->opts, GLUSTERD_GLOBAL_OPT_VERSION,
6669
ret = glusterd_store_options(this, conf->opts);
6671
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_FAIL,
6677
/* For one volume */
6678
ret = glusterd_volinfo_find(volname, &volinfo);
6680
snprintf(err_str, PATH_MAX,
6682
" volinfo for volume %s",
6687
volinfo->snap_max_hard_limit = value;
6689
ret = glusterd_store_volinfo(volinfo,
6690
GLUSTERD_VOLINFO_VER_AC_INCREMENT);
6692
snprintf(err_str, PATH_MAX,
6694
"snap-max-hard-limit for volume %s",
6703
*op_errstr = gf_strdup(err_str);
6704
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_OP_FAILED, "%s",
6711
glusterd_snapshot_config_commit(dict_t *dict, char **op_errstr,
6714
char *volname = NULL;
6715
xlator_t *this = THIS;
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;
6727
GF_ASSERT(op_errstr);
6729
conf = this->private;
6733
ret = dict_get_int32(dict, "config-command", &config_command);
6735
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_COMMAND_NOT_FOUND,
6736
"failed to get config-command type");
6739
if (config_command != GF_SNAP_CONFIG_TYPE_SET) {
6744
ret = dict_get_str(dict, "volname", &volname);
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
6750
gd_get_snap_conf_values_if_present(dict, &hard_limit, &soft_limit);
6753
/* Commit ops for snap-max-hard-limit */
6754
ret = snap_max_hard_limit_set_commit(dict, hard_limit, volname,
6757
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HARD_LIMIT_SET_FAIL,
6758
"snap-max-hard-limit set commit failed.");
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);
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);
6776
if (hard_limit || soft_limit) {
6781
if (!dict_get_str(dict, GLUSTERD_STORE_KEY_SNAP_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);
6787
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6789
"save auto-delete value in conf->opts");
6792
} else if (!dict_get_str(dict, GLUSTERD_STORE_KEY_SNAP_ACTIVATE,
6794
system_conf = _gf_true;
6795
ret = dict_set_dynstr_with_alloc(
6796
conf->opts, GLUSTERD_STORE_KEY_SNAP_ACTIVATE, snap_activate);
6798
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6800
"snap-activate-on-create value in conf->opts");
6805
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
6812
ret = glusterd_get_next_global_opt_version_str(conf->opts,
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");
6821
ret = dict_set_str_sizen(conf->opts, GLUSTERD_GLOBAL_OPT_VERSION,
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");
6830
ret = glusterd_store_options(this, conf->opts);
6832
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_FAIL,
6833
"Failed to store options");
6839
gf_msg_trace(this->name, 0, "Returning %d", ret);
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)
6850
xlator_t *this = THIS;
6851
glusterd_conf_t *priv = NULL;
6852
char key[128] = ""; /* keyprefix is not longer than 64 bytes */
6855
char brick_path[PATH_MAX] = "";
6856
char pidfile[PATH_MAX] = "";
6858
struct glusterd_snap_ops *snap_ops = NULL;
6860
priv = this->private;
6863
GF_ASSERT(op_errstr);
6864
GF_ASSERT(rsp_dict);
6865
GF_ASSERT(keyprefix);
6866
GF_ASSERT(snap_volinfo);
6867
GF_ASSERT(brickinfo);
6869
keylen = snprintf(key, sizeof(key), "%s.brick%d.path", keyprefix, index);
6871
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
6876
ret = snprintf(brick_path, sizeof(brick_path), "%s:%s", brickinfo->hostname,
6879
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
6883
value = gf_strdup(brick_path);
6885
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_STRDUP_FAILED,
6886
"brick_path=%s", brick_path, NULL);
6891
ret = dict_set_dynstrn(rsp_dict, key, keylen, value);
6893
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6900
if (brickinfo->snap_status == -1) {
6901
/* Setting vgname as "Pending Snapshot" */
6902
value = gf_strdup("Pending Snapshot");
6908
keylen = snprintf(key, sizeof(key), "%s.brick%d.vgname", keyprefix,
6910
ret = dict_set_dynstrn(rsp_dict, key, keylen, value);
6912
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6913
"Could not save vgname ");
6922
keylen = snprintf(key, sizeof(key), "%s.brick%d.status", keyprefix, index);
6928
if (brickinfo->status == GF_BRICK_STOPPED) {
6929
value = gf_strdup("No");
6934
ret = dict_set_strn(rsp_dict, key, keylen, value);
6936
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6937
"Could not save brick status");
6942
value = gf_strdup("Yes");
6947
ret = dict_set_strn(rsp_dict, key, keylen, value);
6949
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6950
"Could not save brick status");
6955
GLUSTERD_GET_BRICK_PIDFILE(pidfile, snap_volinfo, brickinfo, priv);
6957
if (gf_is_service_running(pidfile, &pid)) {
6958
keylen = snprintf(key, sizeof(key), "%s.brick%d.pid", keyprefix,
6962
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL,
6967
ret = dict_set_int32n(rsp_dict, key, keylen, pid);
6969
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6970
"Could not save pid %d", pid);
6976
keylen = snprintf(key, sizeof(key), "%s.brick%d", keyprefix, index);
6981
/* While getting snap status we should show relevant information
6982
* for deactivated snaps.
6984
if (snap_volinfo->status == GLUSTERD_STATUS_STOPPED) {
6985
/* Setting vgname as "Deactivated Snapshot" */
6986
value = gf_strdup("N/A (Deactivated Snapshot)");
6992
keylen = snprintf(key, sizeof(key), "%s.brick%d.vgname", keyprefix,
6994
ret = dict_set_dynstrn(rsp_dict, key, keylen, value);
6996
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6997
"Could not save vgname ");
7005
glusterd_snapshot_plugin_by_name(snap_volinfo->snap_plugin, &snap_ops);
7007
ret = snap_ops->details(rsp_dict, brickinfo,
7008
snap_volinfo->snapshot->snapname,
7009
snap_volinfo->volname, index, key);
7012
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_GET_INFO_FAIL,
7026
glusterd_get_single_snap_status(char **op_errstr, dict_t *rsp_dict,
7027
const char *keyprefix, glusterd_snap_t *snap)
7030
xlator_t *this = THIS;
7031
char key[64] = ""; /* keyprefix is "status.snap0" */
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;
7040
GF_ASSERT(op_errstr);
7041
GF_ASSERT(rsp_dict);
7042
GF_ASSERT(keyprefix);
7045
cds_list_for_each_entry_safe(snap_volinfo, tmp_volinfo, &snap->volumes,
7048
keylen = snprintf(key, sizeof(key), "%s.vol%d", keyprefix, volcount);
7050
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7054
cds_list_for_each_entry(brickinfo, &snap_volinfo->bricks, brick_list)
7056
if (!glusterd_is_local_brick(snap_volinfo, brickinfo)) {
7061
ret = glusterd_get_single_brick_status(
7062
op_errstr, rsp_dict, key, brickcount, snap_volinfo, brickinfo);
7065
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7067
"single snap status failed");
7072
keylen = snprintf(brickkey, sizeof(brickkey), "%s.brickcount", key);
7074
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7078
ret = dict_set_int32n(rsp_dict, brickkey, keylen, brickcount);
7080
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7081
"Could not save brick count");
7087
keylen = snprintf(key, sizeof(key), "%s.volcount", keyprefix);
7089
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7094
ret = dict_set_int32n(rsp_dict, key, keylen, volcount);
7096
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7097
"Could not save volcount");
7107
glusterd_get_each_snap_object_status(char **op_errstr, dict_t *rsp_dict,
7108
glusterd_snap_t *snap,
7109
const char *keyprefix)
7112
char key[32] = ""; /* keyprefix is "status.snap0" */
7115
xlator_t *this = THIS;
7117
GF_ASSERT(op_errstr);
7118
GF_ASSERT(rsp_dict);
7120
GF_ASSERT(keyprefix);
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
7125
keylen = snprintf(key, sizeof(key), "%s.snapname", keyprefix);
7127
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7132
temp = gf_strdup(snap->snapname);
7137
ret = dict_set_dynstrn(rsp_dict, key, keylen, temp);
7139
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7147
keylen = snprintf(key, sizeof(key), "%s.uuid", keyprefix);
7149
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7154
temp = gf_strdup(uuid_utoa(snap->snap_id));
7160
ret = dict_set_dynstrn(rsp_dict, key, keylen, temp);
7162
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7170
ret = glusterd_get_single_snap_status(op_errstr, rsp_dict, keyprefix, snap);
7172
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7173
"Could not get single snap status");
7177
keylen = snprintf(key, sizeof(key), "%s.volcount", keyprefix);
7183
ret = dict_set_int32n(rsp_dict, key, keylen, 1);
7185
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7186
"Could not save volcount");
7197
glusterd_get_snap_status_of_volume(char **op_errstr, dict_t *rsp_dict,
7198
char *volname, char *keyprefix)
7201
glusterd_volinfo_t *snap_volinfo = NULL;
7202
glusterd_volinfo_t *temp_volinfo = NULL;
7203
glusterd_volinfo_t *volinfo = NULL;
7205
xlator_t *this = THIS;
7206
glusterd_conf_t *priv = NULL;
7209
priv = this->private;
7212
GF_ASSERT(op_errstr);
7213
GF_ASSERT(rsp_dict);
7215
GF_ASSERT(keyprefix);
7217
ret = glusterd_volinfo_find(volname, &volinfo);
7219
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
7220
"Failed to get volinfo of "
7226
cds_list_for_each_entry_safe(snap_volinfo, temp_volinfo,
7227
&volinfo->snap_volumes, snapvol_list)
7229
ret = snprintf(key, sizeof(key), "status.snap%d.snapname", i);
7231
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7235
ret = dict_set_dynstr_with_alloc(rsp_dict, key,
7236
snap_volinfo->snapshot->snapname);
7238
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7247
ret = dict_set_int32_sizen(rsp_dict, "status.snapcount", i);
7249
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7250
"Failed to save snapcount");
7259
glusterd_get_all_snapshot_status(dict_t *dict, char **op_errstr,
7265
glusterd_conf_t *priv = NULL;
7266
glusterd_snap_t *snap = NULL;
7267
glusterd_snap_t *tmp_snap = NULL;
7268
xlator_t *this = THIS;
7270
priv = this->private;
7274
GF_ASSERT(op_errstr);
7276
cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list)
7278
ret = snprintf(key, sizeof(key), "status.snap%d.snapname", i);
7280
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
7284
ret = dict_set_dynstr_with_alloc(rsp_dict, key, snap->snapname);
7286
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7295
ret = dict_set_int32_sizen(rsp_dict, "status.snapcount", i);
7297
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7298
"Could not save snapcount");
7308
glusterd_snapshot_status_commit(dict_t *dict, char **op_errstr,
7311
xlator_t *this = THIS;
7313
glusterd_conf_t *conf = NULL;
7315
char *snapname = NULL;
7316
glusterd_snap_t *snap = NULL;
7317
char *volname = NULL;
7320
GF_ASSERT(op_errstr);
7322
conf = this->private;
7325
ret = dict_get_int32(dict, "sub-cmd", &cmd);
7327
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7328
"Failed to get status cmd type");
7332
ret = dict_set_int32_sizen(rsp_dict, "sub-cmd", cmd);
7334
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7335
"Could not save status cmd in rsp dictionary");
7339
case GF_SNAP_STATUS_TYPE_ALL: {
7340
ret = glusterd_get_all_snapshot_status(dict, op_errstr, rsp_dict);
7342
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7344
"get snapshot status");
7349
case GF_SNAP_STATUS_TYPE_ITER:
7350
case GF_SNAP_STATUS_TYPE_SNAP: {
7351
ret = dict_get_str(dict, "snapname", &snapname);
7353
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7359
snap = glusterd_find_snap_by_name(snapname);
7361
ret = gf_asprintf(op_errstr,
7369
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL,
7371
"get snap volinfo");
7374
ret = glusterd_get_each_snap_object_status(op_errstr, rsp_dict,
7375
snap, "status.snap0");
7377
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7379
"get status of snap");
7383
ret = dict_set_int32_sizen(rsp_dict, "status.snapcount", 1);
7385
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7387
"set snapcount to 1");
7392
case GF_SNAP_STATUS_TYPE_VOL: {
7393
ret = dict_get_str(dict, "volname", &volname);
7395
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7397
" get volume name");
7401
ret = glusterd_get_snap_status_of_volume(op_errstr, rsp_dict,
7402
volname, "status.vol0");
7404
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7406
" glusterd_get_snap_status_of_volume "
7418
glusterd_handle_snap_limit(dict_t *dict, dict_t *rsp_dict)
7421
xlator_t *this = THIS;
7422
glusterd_conf_t *priv = NULL;
7423
uint64_t effective_max_limit = 0;
7424
int64_t volcount = 0;
7426
char *volname = NULL;
7429
char msg[PATH_MAX] = "";
7430
glusterd_volinfo_t *volinfo = NULL;
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;
7439
GF_ASSERT(rsp_dict);
7441
priv = this->private;
7444
ret = dict_get_int64(dict, "volcount", &volcount);
7446
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7447
"failed to get the volcount");
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);
7455
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7456
"failed to get the "
7461
ret = glusterd_volinfo_find(volname, &volinfo);
7463
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
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
7474
gd_get_snap_conf_values_if_present(priv->opts, &opt_max_hard,
7477
/* The minimum of the 2 limits i.e system wide limit and
7478
volume wide limit will be considered
7480
if (volinfo->snap_max_hard_limit < opt_max_hard)
7481
effective_max_limit = volinfo->snap_max_hard_limit;
7483
effective_max_limit = opt_max_hard;
7485
limit = (opt_max_soft * effective_max_limit) / 100;
7487
count = volinfo->snap_count - limit;
7491
tmp_volinfo = cds_list_entry(volinfo->snap_volumes.next,
7492
glusterd_volinfo_t, snapvol_list);
7493
snap = tmp_volinfo->snapshot;
7496
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SOFT_LIMIT_REACHED,
7499
") of volume %s is reached. "
7500
"Deleting snapshot %s.",
7501
limit, volinfo->volname, snap->snapname);
7503
snprintf(msg, sizeof(msg),
7506
snap->snapname, uuid_utoa(snap->snap_id));
7510
snap->snap_status = GD_SNAP_STATUS_DECOMMISSION;
7511
ret = glusterd_store_snap(snap);
7513
gf_msg(this->name, GF_LOG_ERROR, 0,
7514
GD_MSG_SNAP_OBJECT_STORE_FAIL,
7516
"not store snap object %s",
7521
ret = glusterd_snap_remove(rsp_dict, snap, _gf_true, _gf_true,
7524
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
7525
"failed to remove snap %s", snap->snapname);
7528
UNLOCK(&snap->lock);
7529
if (is_origin_glusterd(dict) == _gf_true) {
7531
gf_event(EVENT_SNAPSHOT_DELETE_FAILED, "%s", msg);
7533
gf_event(EVENT_SNAPSHOT_DELETED, "%s", msg);
7542
glusterd_snapshot_clone_postvalidate(dict_t *dict, int32_t op_ret,
7543
char **op_errstr, dict_t *rsp_dict)
7545
xlator_t *this = THIS;
7546
glusterd_conf_t *priv = NULL;
7548
int32_t cleanup = 0;
7549
glusterd_snap_t *snap = NULL;
7550
glusterd_volinfo_t *snap_vol = NULL;
7551
char *clonename = NULL;
7554
GF_ASSERT(rsp_dict);
7556
priv = this->private;
7559
ret = dict_get_str(dict, "clonename", &clonename);
7561
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7567
ret = glusterd_volinfo_find(clonename, &snap_vol);
7569
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
7570
"unable to find clone "
7577
snap = snap_vol->snapshot;
7580
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
7581
"Snapshot volume is null");
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 *
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);
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.
7603
ret = glusterd_snapobject_delete(snap);
7605
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
7611
snap_vol->snapshot = NULL;
7618
glusterd_snapshot_create_postvalidate(dict_t *dict, int32_t op_ret,
7619
char **op_errstr, dict_t *rsp_dict)
7621
xlator_t *this = THIS;
7622
glusterd_conf_t *priv = NULL;
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;
7636
GF_ASSERT(rsp_dict);
7638
priv = this->private;
7642
ret = dict_get_int32(dict, "cleanup", &cleanup);
7643
if (!ret && cleanup) {
7644
ret = glusterd_do_snap_cleanup(dict, op_errstr, rsp_dict);
7646
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CLEANUP_FAIL,
7648
"operation failed");
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.
7661
ret = dict_get_str(dict, "snapname", &snapname);
7663
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7669
snap = glusterd_find_snap_by_name(snapname);
7671
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
7672
"unable to find snap "
7678
snap->snap_status = GD_SNAP_STATUS_IN_USE;
7679
ret = glusterd_store_snap(snap);
7681
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_OBJECT_STORE_FAIL,
7682
"Could not store snap"
7688
ret = glusterd_snapshot_update_snaps_post_validate(dict, op_errstr,
7691
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
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. *
7704
* Also check, if hard limit and soft limit is reached in case *
7705
* of successfully creating the snapshot, and generate the event *
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);
7711
if (snap_activate == _gf_true) {
7712
gf_event(EVENT_SNAPSHOT_ACTIVATED,
7715
snap->snapname, uuid_utoa(snap->snap_id));
7718
ret = dict_get_str(dict, "volname1", &volname);
7720
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7721
"Failed to get volname.");
7725
ret = glusterd_volinfo_find(volname, &volinfo);
7727
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
7728
"Failed to get volinfo.");
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
7736
gd_get_snap_conf_values_if_present(priv->opts, &opt_hard_max,
7739
if (volinfo->snap_max_hard_limit < opt_hard_max)
7740
effective_max_limit = volinfo->snap_max_hard_limit;
7742
effective_max_limit = opt_hard_max;
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. *
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));
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));
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.
7768
ret = dict_get_str_boolean(priv->opts, GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE,
7770
if (_gf_true == ret) {
7771
ret = glusterd_handle_snap_limit(dict, rsp_dict);
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 */
7785
glusterd_snapshot(dict_t *dict, char **op_errstr, uint32_t *op_errno,
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] = "";
7796
GF_ASSERT(rsp_dict);
7797
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
7799
priv = this->private;
7802
ret = dict_get_int32(dict, "type", &snap_command);
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");
7810
switch (snap_command) {
7811
case (GF_SNAP_OPTION_TYPE_CREATE):
7812
ret = glusterd_snapshot_create_commit(dict, op_errstr, op_errno,
7815
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CREATION_FAIL,
7822
case (GF_SNAP_OPTION_TYPE_CLONE):
7823
ret = glusterd_snapshot_clone_commit(dict, op_errstr, rsp_dict);
7825
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CLONE_FAILED,
7832
case GF_SNAP_OPTION_TYPE_CONFIG:
7833
ret = glusterd_snapshot_config_commit(dict, op_errstr, rsp_dict);
7835
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CONFIG_FAIL,
7836
"snapshot config failed");
7841
case GF_SNAP_OPTION_TYPE_DELETE:
7842
ret = glusterd_snapshot_remove_commit(dict, op_errstr, rsp_dict);
7844
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
7848
/* If error string is already set
7853
ret = dict_get_str(dict, "snapname", &snap_name);
7855
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7856
"Failed to get snapname");
7860
snprintf(temp, sizeof(temp),
7861
"Snapshot %s might "
7862
"not be in an usable state.",
7865
*op_errstr = gf_strdup(temp);
7871
case GF_SNAP_OPTION_TYPE_RESTORE:
7872
ret = glusterd_snapshot_restore(dict, op_errstr, rsp_dict);
7874
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
7876
"restore snapshot");
7881
case GF_SNAP_OPTION_TYPE_ACTIVATE:
7882
ret = glusterd_snapshot_activate_commit(dict, op_errstr, rsp_dict);
7884
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
7886
"activate snapshot");
7892
case GF_SNAP_OPTION_TYPE_DEACTIVATE:
7893
ret = glusterd_snapshot_deactivate_commit(dict, op_errstr,
7896
gf_msg(this->name, GF_LOG_WARNING, 0,
7897
GD_MSG_SNAP_DEACTIVATE_FAIL,
7899
"deactivate snapshot");
7905
case GF_SNAP_OPTION_TYPE_STATUS:
7906
ret = glusterd_snapshot_status_commit(dict, op_errstr, rsp_dict);
7908
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_STATUS_FAIL,
7910
"show snapshot status");
7916
gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
7917
"invalid snap command");
7929
glusterd_snapshot_brickop(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
7932
int64_t vol_count = 0;
7936
char *volname = NULL;
7937
int32_t snap_command = 0;
7938
xlator_t *this = THIS;
7939
char *op_type = NULL;
7942
GF_ASSERT(rsp_dict);
7944
ret = dict_get_int32(dict, "type", &snap_command);
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");
7952
switch (snap_command) {
7953
case GF_SNAP_OPTION_TYPE_CREATE:
7955
/* op_type with tell us whether its pre-commit operation
7958
ret = dict_get_str(dict, "operation-type", &op_type);
7960
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7966
if (strcmp(op_type, "pre") == 0) {
7967
/* BRICK OP PHASE for enabling barrier, Enable barrier
7968
* if its a pre-commit operation
7970
ret = glusterd_set_barrier_value(dict, "enable");
7972
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
7974
"set barrier value as enable in dict");
7977
} else if (strcmp(op_type, "post") == 0) {
7978
/* BRICK OP PHASE for disabling barrier, Disable barrier
7979
* if its a post-commit operation
7981
ret = glusterd_set_barrier_value(dict, "disable");
7983
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
7985
"set barrier value as disable in "
7991
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
7996
ret = dict_get_int64(dict, "volcount", &vol_count);
7999
while (count <= vol_count) {
8000
keylen = snprintf(key, sizeof(key), "volname%" PRId64, count);
8001
ret = dict_get_strn(dict, key, keylen, &volname);
8003
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8004
"Unable to get volname");
8007
ret = dict_set_str_sizen(dict, "volname", volname);
8011
ret = gd_brick_op_phase(GD_OP_SNAP, NULL, dict, op_errstr);
8018
dict_del_sizen(dict, "volname");
8021
case GF_SNAP_OPTION_TYPE_DELETE:
8032
glusterd_snapshot_prevalidate(dict_t *dict, char **op_errstr, dict_t *rsp_dict,
8035
int snap_command = 0;
8036
xlator_t *this = THIS;
8040
GF_ASSERT(rsp_dict);
8041
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
8043
ret = dict_get_int32(dict, "type", &snap_command);
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");
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);
8056
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
8058
"pre-validation failed");
8063
case (GF_SNAP_OPTION_TYPE_CLONE):
8064
ret = glusterd_snapshot_clone_prevalidate(dict, op_errstr, rsp_dict,
8067
gf_msg(this->name, GF_LOG_WARNING, 0,
8068
GD_MSG_SNAP_CLONE_PREVAL_FAILED,
8070
"pre-validation failed");
8075
case (GF_SNAP_OPTION_TYPE_CONFIG):
8076
ret = glusterd_snapshot_config_prevalidate(dict, op_errstr,
8079
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CONFIG_FAIL,
8081
"pre-validation failed");
8086
case GF_SNAP_OPTION_TYPE_RESTORE:
8087
ret = glusterd_snapshot_restore_prevalidate(dict, op_errstr,
8088
op_errno, rsp_dict);
8090
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
8092
"validation failed");
8097
case GF_SNAP_OPTION_TYPE_ACTIVATE:
8098
ret = glusterd_snapshot_activate_deactivate_prevalidate(
8099
dict, op_errstr, op_errno, rsp_dict, _gf_true);
8101
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
8102
"Snapshot activate "
8103
"validation failed");
8107
case GF_SNAP_OPTION_TYPE_DEACTIVATE:
8108
ret = glusterd_snapshot_activate_deactivate_prevalidate(
8109
dict, op_errstr, op_errno, rsp_dict, _gf_false);
8111
gf_msg(this->name, GF_LOG_WARNING, 0,
8112
GD_MSG_SNAP_DEACTIVATE_FAIL,
8113
"Snapshot deactivate validation failed");
8117
case GF_SNAP_OPTION_TYPE_DELETE:
8118
ret = glusterd_snapshot_remove_prevalidate(dict, op_errstr,
8119
op_errno, rsp_dict);
8121
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
8123
"validation failed");
8128
case GF_SNAP_OPTION_TYPE_STATUS:
8129
ret = glusterd_snapshot_status_prevalidate(dict, op_errstr,
8130
op_errno, rsp_dict);
8132
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_STATUS_FAIL,
8134
"validation failed");
8140
gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
8141
"invalid snap command");
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.
8156
* @param volname name of the volume which is being restored
8158
* @return 0 on success or -1 on failure
8161
glusterd_remove_trashpath(char *volname)
8164
char delete_path[PATH_MAX] = {
8167
xlator_t *this = THIS;
8168
glusterd_conf_t *priv = NULL;
8169
struct stat stbuf = {
8174
priv = this->private;
8178
len = snprintf(delete_path, sizeof(delete_path),
8179
"%s/" GLUSTERD_TRASH "/vols-%s.deleted", priv->workdir,
8181
if ((len < 0) || (len >= sizeof(delete_path))) {
8185
ret = sys_lstat(delete_path, &stbuf);
8187
/* If the trash dir does not exist, return *
8190
if (errno == ENOENT) {
8194
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8202
/* Delete the backup copy of volume folder */
8203
ret = recursive_rmdir(delete_path);
8205
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8217
/* This function is called if snapshot restore operation
8218
* is successful. It will cleanup the backup files created
8219
* during the restore operation.
8221
* @param rsp_dict Response dictionary
8222
* @param volinfo volinfo of the volume which is being restored
8223
* @param snap snap object
8225
* @return 0 on success or -1 on failure
8228
glusterd_snapshot_restore_cleanup(dict_t *rsp_dict, char *volname,
8229
glusterd_snap_t *snap)
8233
GF_ASSERT(rsp_dict);
8237
/* Now delete the snap entry. */
8238
ret = glusterd_snap_remove(rsp_dict, snap, _gf_false, _gf_true, _gf_false);
8240
gf_msg(THIS->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
8247
/* Delete the backup copy of volume folder */
8248
ret = glusterd_remove_trashpath(volname);
8250
gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8261
/* This function is called when the snapshot restore operation failed
8262
* for some reasons. In such case we revert the restore operation.
8264
* @param volinfo volinfo of the origin volume
8266
* @return 0 on success and -1 on failure
8269
glusterd_snapshot_revert_partial_restored_vol(glusterd_volinfo_t *volinfo)
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;
8282
priv = this->private;
8286
GLUSTERD_GET_VOLUME_DIR(pathname, volinfo, priv);
8288
len = snprintf(trash_path, sizeof(trash_path),
8289
"%s/" GLUSTERD_TRASH "/vols-%s.deleted", priv->workdir,
8291
if ((len < 0) || (len >= sizeof(trash_path))) {
8292
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
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);
8302
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8309
/* Now move the backup copy of the vols to its original
8311
ret = sys_rename(trash_path, pathname);
8313
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8314
"Failed to rename folder "
8316
trash_path, pathname);
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 "
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,
8335
cds_list_add_tail(&snap_vol->snapvol_list, &reverted_vol->snap_volumes);
8337
cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
8340
* If the brick is not of this peer, or snapshot is *
8341
* missed for the brick don't restore the xattr for it *
8343
if ((!gf_uuid_compare(brickinfo->uuid, MY_UUID)) &&
8344
(brickinfo->snap_status != -1)) {
8346
* We need to restore volume id of all snap *
8347
* bricks to volume id of the snap volume. *
8349
ret = sys_lsetxattr(brickinfo->path, GF_XATTR_VOL_ID_KEY,
8350
snap_vol->volume_id,
8351
sizeof(snap_vol->volume_id), XATTR_REPLACE);
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);
8368
/* This function is called when glusterd is started and we need
8369
* to revert a failed snapshot restore.
8371
* @param snap snapshot object of the restored snap
8373
* @return 0 on success and -1 on failure
8376
glusterd_snapshot_revert_restore_from_snap(glusterd_snap_t *snap)
8379
char volname[PATH_MAX] = "";
8380
glusterd_volinfo_t *snap_volinfo = NULL;
8381
glusterd_volinfo_t *volinfo = NULL;
8384
/* TODO : As of now there is only one volume in snapshot.
8385
* Change this when multiple volume snapshot is introduced
8387
snap_volinfo = cds_list_entry(snap->volumes.next, glusterd_volinfo_t,
8390
gf_strncpy(volname, snap_volinfo->parent_volname, sizeof(volname));
8392
ret = glusterd_volinfo_find(volname, &volinfo);
8394
gf_msg(THIS->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
8395
"Could not get volinfo of "
8397
snap_volinfo->parent_volname);
8401
ret = glusterd_snapshot_revert_partial_restored_vol(volinfo);
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",
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);
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
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
8427
* @return 0 on success and -1 on failure
8430
glusterd_snapshot_restore_postop(dict_t *dict, int32_t op_ret, char **op_errstr,
8435
char *volname = NULL;
8437
glusterd_snap_t *snap = NULL;
8438
glusterd_volinfo_t *volinfo = NULL;
8439
xlator_t *this = THIS;
8442
GF_ASSERT(rsp_dict);
8444
ret = dict_get_str(dict, "snapname", &name);
8446
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8448
"name failed (volume: %s)",
8453
snap = glusterd_find_snap_by_name(name);
8455
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_NOT_FOUND,
8456
"Snapshot (%s) does not exist", name);
8461
/* TODO: fix this when multiple volume support will come */
8462
ret = dict_get_str(dict, "volname1", &volname);
8464
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8465
"failed to get volume name");
8469
ret = glusterd_volinfo_find(volname, &volinfo);
8471
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
8472
"Volume (%s) does not exist ", volname);
8476
ret = dict_get_str(dict, "snapname", &name);
8478
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
8480
"name failed (volume: %s)",
8485
snap = glusterd_find_snap_by_name(name);
8487
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_SNAP_NOT_FOUND,
8488
"snap %s is not found", name);
8493
/* On success perform the cleanup operation */
8495
ret = glusterd_snapshot_restore_cleanup(rsp_dict, volname, snap);
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",
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);
8510
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
8511
"Failed to remove backup dir");
8518
ret = glusterd_snapshot_revert_partial_restored_vol(volinfo);
8520
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_REVERT_FAIL,
8522
"restore operation for %s volume",
8527
snap->snap_status = GD_SNAP_STATUS_IN_USE;
8528
/* We need to save this in disk */
8529
ret = glusterd_store_snap(snap);
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);
8536
/* After restore fails, we have to remove mount point for
8537
* deactivated snaps which was created at start of restore op.
8540
if (volinfo->status == GLUSTERD_STATUS_STOPPED) {
8541
ret = glusterd_snap_unmount(this, volinfo);
8543
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_UMOUNT_FAIL,
8544
"Failed to unmounts for %s", snap->snapname);
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);
8560
glusterd_snapshot_postvalidate(dict_t *dict, int32_t op_ret, char **op_errstr,
8563
int snap_command = 0;
8564
xlator_t *this = THIS;
8568
GF_ASSERT(rsp_dict);
8570
ret = dict_get_int32(dict, "type", &snap_command);
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");
8578
switch (snap_command) {
8579
case GF_SNAP_OPTION_TYPE_CREATE:
8580
ret = glusterd_snapshot_create_postvalidate(dict, op_ret, op_errstr,
8583
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
8585
"post-validation failed");
8588
glusterd_fetchsnap_notify(this);
8590
case GF_SNAP_OPTION_TYPE_CLONE:
8591
ret = glusterd_snapshot_clone_postvalidate(dict, op_ret, op_errstr,
8594
gf_msg(this->name, GF_LOG_WARNING, 0,
8595
GD_MSG_SNAP_CLONE_POSTVAL_FAILED,
8597
"post-validation failed");
8600
glusterd_fetchsnap_notify(this);
8602
case GF_SNAP_OPTION_TYPE_DELETE:
8604
gf_msg_debug(this->name, 0,
8605
"op_ret = %d. Not performing delete "
8611
ret = glusterd_snapshot_update_snaps_post_validate(dict, op_errstr,
8614
gf_msg(this->name, GF_LOG_ERROR, 0,
8615
GD_MSG_MISSED_SNAP_LIST_STORE_FAIL,
8617
"update missed snaps list");
8620
glusterd_fetchsnap_notify(this);
8622
case GF_SNAP_OPTION_TYPE_RESTORE:
8623
ret = glusterd_snapshot_update_snaps_post_validate(dict, op_errstr,
8626
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
8628
"update missed snaps list");
8632
ret = glusterd_snapshot_restore_postop(dict, op_ret, op_errstr,
8635
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
8637
"perform snapshot restore post-op");
8640
glusterd_fetchsnap_notify(this);
8642
case GF_SNAP_OPTION_TYPE_ACTIVATE:
8643
case GF_SNAP_OPTION_TYPE_DEACTIVATE:
8644
glusterd_fetchsnap_notify(this);
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*/
8655
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_COMMAND_NOT_FOUND,
8656
"invalid snap command");
8666
glusterd_handle_snapshot_fn(rpcsvc_request_t *req)
8669
dict_t *dict = NULL;
8670
gf_cli_req cli_req = {
8673
glusterd_op_t cli_op = GD_OP_SNAP;
8675
char *host_uuid = NULL;
8676
char err_str[2048] = "";
8677
xlator_t *this = THIS;
8678
uint32_t op_errno = 0;
8682
ret = xdr_to_generic(req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);
8684
req->rpc_err = GARBAGE_ARGS;
8685
gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_GARBAGE_ARGS, NULL);
8689
if (cli_req.dict.dict_len > 0) {
8694
ret = dict_unserialize(cli_req.dict.dict_val, cli_req.dict.dict_len,
8697
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_UNSERIALIZE_FAIL,
8699
"unserialize req-buffer to dictionary");
8700
snprintf(err_str, sizeof(err_str),
8706
dict->extra_stdfree = cli_req.dict.dict_val;
8708
host_uuid = gf_strdup(uuid_utoa(MY_UUID));
8709
if (host_uuid == NULL) {
8710
snprintf(err_str, sizeof(err_str),
8712
"the uuid of local glusterd");
8716
ret = dict_set_dynstr_sizen(dict, "host-uuid", host_uuid);
8723
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
8724
"request dict length is %d", cli_req.dict.dict_len);
8728
ret = dict_get_int32(dict, "type", &type);
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",
8738
case GF_SNAP_OPTION_TYPE_CREATE:
8739
ret = glusterd_handle_snapshot_create(req, cli_op, dict, err_str,
8742
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CREATION_FAIL,
8743
"Snapshot create failed: %s", err_str);
8747
case GF_SNAP_OPTION_TYPE_CLONE:
8748
ret = glusterd_handle_snapshot_clone(req, cli_op, dict, err_str,
8751
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CLONE_FAILED,
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));
8762
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_RESTORE_FAIL,
8763
"Snapshot restore failed: %s", err_str);
8767
case GF_SNAP_OPTION_TYPE_INFO:
8768
ret = glusterd_handle_snapshot_info(req, cli_op, dict, err_str,
8771
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_INFO_FAIL,
8772
"Snapshot info failed");
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);
8779
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_LIST_GET_FAIL,
8780
"Snapshot list failed");
8783
case GF_SNAP_OPTION_TYPE_CONFIG:
8784
ret = glusterd_handle_snapshot_config(req, cli_op, dict, err_str,
8787
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_CONFIG_FAIL,
8788
"snapshot config failed");
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));
8795
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_REMOVE_FAIL,
8796
"Snapshot delete failed: %s", err_str);
8799
case GF_SNAP_OPTION_TYPE_ACTIVATE:
8800
ret = glusterd_mgmt_v3_initiate_snap_phases(req, cli_op, dict);
8802
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_ACTIVATE_FAIL,
8803
"Snapshot activate failed: %s", err_str);
8806
case GF_SNAP_OPTION_TYPE_DEACTIVATE:
8807
ret = glusterd_mgmt_v3_initiate_snap_phases(req, cli_op, dict);
8809
gf_msg(this->name, GF_LOG_WARNING, 0,
8810
GD_MSG_SNAP_DEACTIVATE_FAIL,
8811
"Snapshot deactivate failed: %s", err_str);
8814
case GF_SNAP_OPTION_TYPE_STATUS:
8815
ret = glusterd_handle_snapshot_status(req, cli_op, dict, err_str,
8818
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SNAP_STATUS_FAIL,
8819
"Snapshot status failed: %s", err_str);
8823
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COMMAND_NOT_FOUND,
8824
"Unknown snapshot request "
8827
ret = -1; /* Failure */
8832
if (err_str[0] == '\0')
8833
snprintf(err_str, sizeof(err_str), "Operation failed");
8835
if (ret && (op_errno == 0))
8836
op_errno = EG_INTRNL;
8838
ret = glusterd_op_send_cli_response(cli_op, ret, op_errno, req, dict,
8846
glusterd_handle_snapshot(rpcsvc_request_t *req)
8848
return glusterd_big_locked_handler(req, glusterd_handle_snapshot_fn);
8852
glusterd_free_snap_op(glusterd_snap_op_t *snap_op)
8855
if (snap_op->brick_path)
8856
GF_FREE(snap_op->brick_path);
8863
glusterd_free_missed_snapinfo(glusterd_missed_snap_info *missed_snapinfo)
8865
glusterd_snap_op_t *snap_opinfo = NULL;
8866
glusterd_snap_op_t *tmp = NULL;
8868
if (missed_snapinfo) {
8869
cds_list_for_each_entry_safe(snap_opinfo, tmp,
8870
&missed_snapinfo->snap_ops, snap_ops_list)
8872
glusterd_free_snap_op(snap_opinfo);
8876
if (missed_snapinfo->node_uuid)
8877
GF_FREE(missed_snapinfo->node_uuid);
8879
if (missed_snapinfo->snap_uuid)
8880
GF_FREE(missed_snapinfo->snap_uuid);
8882
GF_FREE(missed_snapinfo);
8886
/* Look for duplicates and accordingly update the list */
8888
glusterd_update_missed_snap_entry(glusterd_missed_snap_info *missed_snapinfo,
8889
glusterd_snap_op_t *missed_snap_op)
8892
glusterd_snap_op_t *snap_opinfo = NULL;
8893
gf_boolean_t match = _gf_false;
8894
xlator_t *this = THIS;
8896
GF_ASSERT(missed_snapinfo);
8897
GF_ASSERT(missed_snap_op);
8899
cds_list_for_each_entry(snap_opinfo, &missed_snapinfo->snap_ops,
8902
/* If the entry is not for the same snap_vol_id
8905
if (strcmp(snap_opinfo->snap_vol_id, missed_snap_op->snap_vol_id))
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
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);
8924
glusterd_free_snap_op(missed_snap_op);
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
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;
8944
glusterd_free_snap_op(missed_snap_op);
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);
8954
cds_list_add_tail(&missed_snap_op->snap_ops_list,
8955
&missed_snapinfo->snap_ops);
8960
gf_msg_trace(this->name, 0, "Returning %d", ret);
8964
/* Add new missed snap entry to the missed_snaps list. */
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)
8971
char *save_ptr = NULL;
8972
char node_snap_info[PATH_MAX] = "";
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;
8981
GF_ASSERT(missed_info);
8982
GF_ASSERT(snap_vol_id);
8983
GF_ASSERT(brick_path);
8985
priv = this->private;
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);
8992
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL,
8993
"Failed to create new missed snap object.");
8998
missed_snap_op->snap_vol_id = gf_strdup(snap_vol_id);
8999
if (!missed_snap_op->snap_vol_id) {
9003
missed_snap_op->brick_path = gf_strdup(brick_path);
9004
if (!missed_snap_op->brick_path) {
9008
missed_snap_op->brick_num = brick_num;
9009
missed_snap_op->op = snap_op;
9010
missed_snap_op->status = snap_status;
9012
/* Look for other entries for the same node and same snap */
9013
cds_list_for_each_entry(missed_snapinfo, &priv->missed_snaps_list,
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 */
9026
if (match == _gf_false) {
9027
/* First snap op missed for the brick */
9028
ret = glusterd_missed_snapinfo_new(&missed_snapinfo);
9030
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL,
9031
"Failed to create missed snapinfo");
9034
free_missed_snap_info = _gf_true;
9035
buf = strtok_r(missed_info, ":", &save_ptr);
9040
missed_snapinfo->node_uuid = gf_strdup(buf);
9041
if (!missed_snapinfo->node_uuid) {
9046
buf = strtok_r(NULL, ":", &save_ptr);
9051
missed_snapinfo->snap_uuid = gf_strdup(buf);
9052
if (!missed_snapinfo->snap_uuid) {
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);
9065
ret = glusterd_update_missed_snap_entry(missed_snapinfo,
9068
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL,
9069
"Failed to update existing missed snap entry.");
9076
glusterd_free_snap_op(missed_snap_op);
9078
if (missed_snapinfo && (free_missed_snap_info == _gf_true))
9079
glusterd_free_missed_snapinfo(missed_snapinfo);
9082
gf_msg_trace(this->name, 0, "Returning %d", ret);
9086
/* Add missing snap entries to the in-memory conf->missed_snap_list */
9088
glusterd_add_missed_snaps_to_list(dict_t *dict, int32_t missed_snap_count)
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] = "";
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;
9110
priv = this->private;
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);
9119
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
9120
"Unable to fetch %s", key);
9124
gf_msg_debug(this->name, 0, "missed_snap_entry = %s", buf);
9126
/* Need to make a duplicate string coz the same dictionary *
9127
* is resent to the non-originator nodes */
9128
tmp = gf_strdup(buf);
9134
/* Fetch the node-id, snap-id, brick_num,
9135
* brick_path, snap_op and snap status
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));
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");
9154
snprintf(missed_info, sizeof(missed_info), "%s:%s", nodeid, snap_uuid);
9156
ret = glusterd_add_new_entry_to_list(missed_info, snap_vol_id,
9157
brick_num, brick_path, snap_op,
9160
gf_msg(this->name, GF_LOG_ERROR, 0,
9161
GD_MSG_MISSED_SNAP_LIST_STORE_FAIL,
9162
"Failed to store missed snaps_list");
9175
gf_msg_trace(this->name, 0, "Returning %d", ret);
9180
glusterd_bricks_snapshot_restore(dict_t *rsp_dict, glusterd_volinfo_t *snap_vol,
9181
gf_boolean_t *retain_origin_path)
9183
int32_t brick_count = -1;
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;
9193
GF_ASSERT(snap_vol);
9196
glusterd_snapshot_plugin_by_name(snap_vol->snap_plugin, &snap_ops);
9198
cds_list_for_each_entry(brickinfo, &snap_vol->bricks, brick_list)
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);
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);
9212
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL,
9214
"restore the snapshot %s (%s)",
9215
brickinfo->path, snap_vol->snapshot->snapname);
9216
err = -1; /* We need to record this failure */
9225
gf_msg_trace(this->name, 0, "Returning %d", ret);
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.
9235
* @param orig_vol volinfo of origin volume
9236
* @param snap_vol volinfo of snapshot volume
9238
* @return 0 on success and negative value on error
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)
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;
9256
GF_ASSERT(rsp_dict);
9257
conf = this->private;
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);
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
9269
snap->snap_status = GD_SNAP_STATUS_UNDER_RESTORE;
9271
/* We need to save this in disk so that if node goes
9272
* down the status is in updated state.
9274
ret = glusterd_store_snap(snap);
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);
9283
/* Snap volume must be stopped before performing the
9284
* restore operation.
9286
ret = glusterd_stop_volume(snap_vol);
9288
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_STOP_FAILED,
9294
/* Create a new volinfo for the restored volume */
9295
ret = glusterd_volinfo_dup(snap_vol, &new_volinfo, _gf_true);
9297
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
9298
"Failed to create volinfo");
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);
9311
/* Use the same version as the original version */
9312
new_volinfo->version = orig_vol->version;
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,
9319
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL,
9320
"Failed to restore snap");
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"
9332
ret = glusterd_restore_geo_rep_files(snap_vol);
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);
9340
/* Need not save cksum, as we will copy cksum file in *
9343
ret = glusterd_copy_quota_files(snap_vol, orig_vol, &conf_present);
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);
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);
9356
cds_list_add_tail(&new_volinfo->vol_list, &conf->volumes);
9358
ret = glusterd_store_volinfo(new_volinfo,
9359
GLUSTERD_VOLINFO_VER_AC_INCREMENT);
9361
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_OP_FAILED,
9362
"Failed to store volinfo");
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.
9374
(void)glusterd_volinfo_unref(new_volinfo);
9376
cds_list_for_each_entry_safe(voliter, temp_volinfo,
9377
&orig_vol->snap_volumes, snapvol_list)
9379
cds_list_add_tail(&voliter->snapvol_list,
9380
&new_volinfo->snap_volumes);
9388
glusterd_snapshot_get_volnames_uuids(dict_t *dict, char *volname,
9389
gf_getsnap_name_uuid_rsp *snap_info_rsp)
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;
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,
9406
ret = glusterd_volinfo_find(volname, &volinfo);
9408
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
9409
"Failed to get volinfo of volume %s", volname);
9414
cds_list_for_each_entry_safe(snap_vol, tmp_vol, &volinfo->snap_volumes,
9417
if (GLUSTERD_STATUS_STARTED != snap_vol->status)
9423
snprintf(key, sizeof(key), "snapname.%d", snapcount);
9424
ret = dict_set_dynstr_with_alloc(dict, key,
9425
snap_vol->snapshot->snapname);
9427
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9429
"snap name in dictionary");
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));
9438
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9440
"snap id in dictionary");
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);
9448
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9450
"snap id in dictionary");
9455
ret = dict_set_int32_sizen(dict, "snap-count", snapcount);
9457
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
9458
"Failed to set snapcount");
9463
ret = dict_allocate_and_serialize(dict, &snap_info_rsp->dict.dict_val,
9464
&snap_info_rsp->dict.dict_len);
9474
snap_info_rsp->op_ret = ret;
9475
snap_info_rsp->op_errno = op_errno;
9476
snap_info_rsp->op_errstr = "";