From 096b23f187d0b3ccbed25d8bd02723a61cc4da2d Mon Sep 17 00:00:00 2001 From: shishir gowda Date: Thu, 24 Oct 2013 15:47:14 +0530 Subject: mgmt/glusterd: snapshot config changes Also refactored code in glusterd for create command Additionally, removed brick-op func from mgmt_iniate_all_phases Change-Id: Iddcc332009c5716adee7f2b04c93b352fb983446 Signed-off-by: shishir gowda --- xlators/mgmt/glusterd/src/glusterd-mgmt.c | 8 - xlators/mgmt/glusterd/src/glusterd-snapshot.c | 609 ++++++++++++++++++++------ xlators/mgmt/glusterd/src/glusterd-utils.c | 11 + xlators/mgmt/glusterd/src/glusterd.c | 3 + xlators/mgmt/glusterd/src/glusterd.h | 3 + 5 files changed, 481 insertions(+), 153 deletions(-) (limited to 'xlators') diff --git a/xlators/mgmt/glusterd/src/glusterd-mgmt.c b/xlators/mgmt/glusterd/src/glusterd-mgmt.c index defd8f477..e6f341ada 100644 --- a/xlators/mgmt/glusterd/src/glusterd-mgmt.c +++ b/xlators/mgmt/glusterd/src/glusterd-mgmt.c @@ -1316,14 +1316,6 @@ glusterd_mgmt_v3_initiate_all_phases (rpcsvc_request_t *req, glusterd_op_t op, goto out; } - /* BRICK OP PHASE */ - ret = glusterd_mgmt_v3_brick_op (conf, op, req_dict, - &op_errstr, npeers); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Brick Ops Failed"); - goto out; - } - /* COMMIT OP PHASE */ ret = glusterd_mgmt_v3_commit (conf, op, req_dict, &op_errstr, npeers); diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c index c946e4dbd..87ed711dc 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -44,7 +44,155 @@ #endif int -glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, +glusterd_snapshot_config_limit_prevalidate (dict_t *dict, char **op_errstr, + int config_command) +{ + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + uint64_t limit = 0; + xlator_t *this = NULL; + int ret = -1; + char err_str[PATH_MAX] = {0,}; + glusterd_conf_t *conf = NULL; + + this = THIS; + + GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (*op_errstr); + + conf = this->private; + + GF_ASSERT (conf); + + switch (config_command) { + + case GF_SNAP_CONFIG_SYS_MAX: + ret = dict_get_uint64 (dict, "limit", &limit); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " snapshot limit"); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + if (limit < 0 || limit > GLUSTERD_SNAPS_MAX_LIMIT) { + ret = -1; + snprintf (err_str, PATH_MAX,"Invalid max snap limit " + "%"PRIu64 ". Expected range 0 - %"PRIu64, + limit, conf->snap_max_limit); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + break; + + case GF_SNAP_CONFIG_VOL_MAX: + // volume wide limit + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volume name"); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volinfo for volume %s", volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + ret = dict_get_uint64 (dict, "limit", &limit); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " snapshot limit volinfo for volume %s", + volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + if (limit < 0 || limit > conf->snap_max_limit) { + ret = -1; + snprintf (err_str, PATH_MAX,"Invalid max snap limit " + "%"PRIu64 " for volume %s. Expected range" + " 0 - %"PRIu64, limit, volname, + conf->snap_max_limit); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + break; + + case GF_SNAP_CONFIG_CG_MAX: + break; + + case GF_SNAP_CONFIG_DISPLAY: + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volume name"); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + if (!strncmp (volname, "all", 3)) { + ret = 0; + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volinfo for volume %s", volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + break; + default: + break; + } +out: + return ret; +} + +int +glusterd_snapshot_config_prevalidate (dict_t *dict, char **op_errstr) +{ + int config_command = 0; + xlator_t *this = NULL; + int ret = -1; + + this = THIS; + ret = dict_get_int32 (dict, "config-command", &config_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get config-command type"); + goto out; + } + + switch (config_command) { + case GF_SNAP_CONFIG_SYS_MAX: + case GF_SNAP_CONFIG_VOL_MAX: + case GF_SNAP_CONFIG_CG_MAX: + case GF_SNAP_CONFIG_DISPLAY: + ret = glusterd_snapshot_config_limit_prevalidate (dict, + op_errstr, + config_command); + break; + default: + ret = -1; + gf_log (this->name, GF_LOG_ERROR, "Incorrect config op"); + break; + } +out: + return ret; +} + +int +glusterd_snapshot_create_prevalidate (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { char *volname = NULL; @@ -52,6 +200,49 @@ glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, int64_t volume_count = 0; char volname_buf[PATH_MAX] = {0, }; int64_t i = 0; + xlator_t *this = NULL; + int ret = -1; + + ret = dict_get_int64 (dict, "volcount", &volume_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the volume count"); + goto out; + } + for (i = 0; i < volume_count; i++) { + snprintf (volname_buf, sizeof (volname_buf), + "volname%ld", i+1); + ret = dict_get_str (dict, volname_buf, + &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get volume name"); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get the volinfo for " + "the volume %s", volname); + goto out; + } + if (glusterd_is_defrag_on (volinfo)) { + ret = -1; + gf_log (this->name, GF_LOG_WARNING, + "rebalance process is running " + "for the volume %s", volname); + goto out; + } + //Also check whether geo replication is running + } +out: + return ret; +} + +int +glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ int snap_command = 0; xlator_t *this = NULL; int ret = -1; @@ -61,6 +252,7 @@ glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, GF_ASSERT (this); GF_ASSERT (dict); GF_ASSERT (rsp_dict); //not sure if this is needed, verify. + ret = dict_get_int32 (dict, "type", &snap_command); if (ret) { gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " @@ -69,49 +261,20 @@ glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, } switch (snap_command) { - case (GF_SNAP_OPTION_TYPE_CREATE): - { - ret = dict_get_int64 (dict, "volcount", &volume_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the volume count"); - goto out; - } - for (i = 0; i < volume_count; i++) { - snprintf (volname_buf, sizeof (volname_buf), - "volname%ld", i+1); - ret = dict_get_str (dict, volname_buf, - &volname); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get volume name"); - goto out; - } - ret = glusterd_volinfo_find (volname, &volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get the volinfo for " - "the volume %s", volname); - goto out; - } - if (glusterd_is_defrag_on (volinfo)) { - gf_log (this->name, GF_LOG_WARNING, - "rebalance process is running " - "for the volume %s", volname); - goto out; - } - //Also check whether geo replication is running - } - break; - } + case (GF_SNAP_OPTION_TYPE_CREATE): + ret = glusterd_snapshot_create_prevalidate (dict, op_errstr, + rsp_dict); + break; + + case (GF_SNAP_OPTION_TYPE_CONFIG): + ret = glusterd_snapshot_config_prevalidate (dict, op_errstr); + break; + default: gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); goto out; break; } - - ret = 0; - out: return ret; } @@ -2088,123 +2251,96 @@ out: */ int32_t -glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) +glusterd_snapshot_create_commit (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) { - int ret = -1; - int i = 0; - int snap_command = 0; - int64_t volume_count = 0; - gf_boolean_t is_cg = _gf_false; - char *name = NULL; - char *volname = NULL; - char *tmp = NULL; - char volname_buf[PATH_MAX] = {0, }; - xlator_t *this = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_snap_cg_t *cg = NULL; - glusterd_conf_t *priv = NULL; - uuid_t cg_id; - - this = THIS; + char *name = NULL; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + int64_t volume_count = 0; + char volname_buf[PATH_MAX] = {0, }; + int i = 0; + xlator_t *this = NULL; + int ret = -1; + glusterd_snap_cg_t *cg = NULL; + gf_boolean_t is_cg = _gf_false; + uuid_t cg_id; + glusterd_conf_t *priv = NULL; + char *tmp = NULL; + + ret = dict_get_int64 (dict, "volcount", &volume_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the volume count"); + goto out; + } - GF_ASSERT (this); - GF_ASSERT (dict); - GF_ASSERT (rsp_dict); //not sure if this is needed, verify. + //snap-name should not be set if volume_count > 1 + ret = dict_get_str (dict, "snap-name", &name); + if (volume_count > 1 && !ret) + GF_ASSERT (0); - priv = this->private; - GF_ASSERT (priv); + if (volume_count > 1) { + is_cg = _gf_true; + ret = dict_get_str (dict, "cg-name", &name); + uuid_generate (cg_id); + } else if (volume_count == 1) { + ret = dict_get_str (dict, "snap-name", &name); + } - ret = dict_get_int32 (dict, "type", &snap_command); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " - "the snapshot command"); - goto out; + if (!name) { + name = generate_snapname (volname, NULL, is_cg); + if (!name) { + gf_log (this->name, GF_LOG_ERROR, + "strdup of internal snapname" + " ((%s) failed for the " + "volume %s", name, + volname); + goto out; + } } - switch (snap_command) { - case (GF_SNAP_OPTION_TYPE_CREATE): - { - ret = dict_get_int64 (dict, "volcount", &volume_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the volume count"); - goto out; - } + for (i = 1; i < volume_count + 1; i++) { + snprintf (volname_buf, sizeof (volname_buf), + "volname%d", i); + ret = dict_get_str (dict, volname_buf, + &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get volume name"); + goto out; + } - //snap-name should not be set if volume_count > 1 - ret = dict_get_str (dict, "snap-name", &name); - if (volume_count > 1 && !ret) - GF_ASSERT (0); - - if (volume_count > 1) { - is_cg = _gf_true; - ret = dict_get_str (dict, "cg-name", &name); - uuid_generate (cg_id); - } else if (volume_count == 1) { - ret = dict_get_str (dict, "snap-name", &name); - } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get the volinfo for " + "the volume %s", volname); + goto out; + } - if (!name) { - name = generate_snapname (volname, NULL, is_cg); - if (!name) { - gf_log (this->name, GF_LOG_ERROR, - "strdup of internal snapname" - " ((%s) failed for the " - "volume %s", name, - volname); - goto out; - } - } + tmp = generate_snapname (volname, name, is_cg); + if (!tmp) { + gf_log (this->name, + GF_LOG_ERROR, "strdup " + "failed (%s)", name); + goto out; + } - for (i = 1; i < volume_count + 1; i++) { - snprintf (volname_buf, sizeof (volname_buf), - "volname%d", i); - ret = dict_get_str (dict, volname_buf, - &volname); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get volume name"); - goto out; - } - - ret = glusterd_volinfo_find (volname, &volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get the volinfo for " - "the volume %s", volname); - goto out; - } - - tmp = generate_snapname (volname, name, is_cg); - if (!tmp) { - gf_log (this->name, - GF_LOG_ERROR, "strdup " - "failed (%s)", name); - goto out; - } - - /* TODO: Create a stub where the bricks are - added parallely by worker threads so that - the snap creating happens parallely. - */ - ret = glusterd_do_snap (volinfo, tmp, dict, - is_cg, cg_id); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "taking the " - "snapshot of the volume %s failed", - volname); - goto out; - } - } - break; + /* TODO: Create a stub where the bricks are + added parallely by worker threads so that + the snap creating happens parallely. + */ + ret = glusterd_do_snap (volinfo, tmp, dict, + is_cg, cg_id); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "taking the " + "snapshot of the volume %s failed", + volname); + goto out; } - default: - gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); - goto out; - break; } - if (volume_count > 1) { cg = glusterd_new_snap_cg_object (volume_count); if (!cg) { @@ -2227,6 +2363,187 @@ glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) goto out; } } +out: + return ret; +} + +int +glusterd_snapshot_config_commit (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + uint64_t limit = 0; + xlator_t *this = NULL; + int ret = -1; + char err_str[PATH_MAX] = {0,}; + glusterd_conf_t *conf = NULL; + int config_command = 0; + + this = THIS; + + GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (*op_errstr); + GF_ASSERT (rsp_dict); + + conf = this->private; + + GF_ASSERT (conf); + + ret = dict_get_int32 (dict, "config-command", &config_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get config-command type"); + goto out; + } + + switch (config_command) { + + case GF_SNAP_CONFIG_SYS_MAX: + ret = dict_get_uint64 (dict, "limit", &limit); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " snapshot limit"); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + conf->snap_max_limit = limit; + // TODO: do store + + break; + + case GF_SNAP_CONFIG_VOL_MAX: + // volume wide limit + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volume name"); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volinfo for volume %s", volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + ret = dict_get_uint64 (dict, "limit", &limit); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " snapshot limit volinfo for volume %s", + volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + volinfo->snap_max_limit = limit; + //TODO: do store + break; + + case GF_SNAP_CONFIG_CG_MAX: + break; + case GF_SNAP_CONFIG_DISPLAY: + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volume name"); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + if (!strncmp (volname, "all", 3)) { + limit = conf->snap_max_limit; + } else { + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " volinfo for volume %s", volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", + err_str); + goto out; + } + limit = volinfo->snap_max_limit; + } + + ret = dict_set_uint64 (rsp_dict, "limit", limit); + if (ret) { + snprintf (err_str, PATH_MAX,"Failed to get the" + " set limit for volume %s", + volname); + *op_errstr = gf_strdup (err_str); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + goto out; + } + break; + + default: + break; + } + + ret = dict_set_str (rsp_dict, "volname", volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set the" + " volume name"); + goto out; + } + ret = dict_set_int32 (dict, "config-command", config_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to set config-command type"); + goto out; + } +out: + return ret; +} +int32_t +glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) +{ + + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int32_t snap_command = 0; + int ret = -1; + + this = THIS; + + GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (rsp_dict); //not sure if this is needed, verify. + + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_int32 (dict, "type", &snap_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " + "the snapshot command"); + goto out; + } + + switch (snap_command) { + case (GF_SNAP_OPTION_TYPE_CREATE): + ret = glusterd_snapshot_create_commit (dict, op_errstr, + rsp_dict); + break; + + case GF_SNAP_OPTION_TYPE_CONFIG: + ret = glusterd_snapshot_config_commit (dict, op_errstr, + rsp_dict); + break; + + default: + gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); + goto out; + break; + } + + ret = 0; @@ -2313,12 +2630,14 @@ glusterd_handle_snapshot_fn (rpcsvc_request_t *req) case GF_SNAP_OPTION_TYPE_LIST: ret = glusterd_handle_snapshot_list (req, cli_op, dict); break; + case GF_SNAP_OPTION_TYPE_CONFIG: + ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict); + break; case GF_SNAP_OPTION_TYPE_RESTORE: case GF_SNAP_OPTION_TYPE_DELETE: case GF_SNAP_OPTION_TYPE_START: case GF_SNAP_OPTION_TYPE_STOP: case GF_SNAP_OPTION_TYPE_STATUS: - case GF_SNAP_OPTION_TYPE_CONFIG: gf_log (this->name, GF_LOG_ERROR, "Operation (%d) not " "supported ", type); diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 771b0af5a..1f5cc741b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -427,6 +427,12 @@ glusterd_volinfo_new (glusterd_volinfo_t **volinfo) { glusterd_volinfo_t *new_volinfo = NULL; int32_t ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + this = THIS; + + conf = this->private; GF_ASSERT (volinfo); @@ -455,6 +461,11 @@ glusterd_volinfo_new (glusterd_volinfo_t **volinfo) goto out; } + if (conf) + new_volinfo->snap_max_limit = conf->snap_max_limit; + else + new_volinfo->snap_max_limit = GLUSTERD_SNAPS_MAX_LIMIT; + new_volinfo->xl = THIS; *volinfo = new_volinfo; diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index c0531d375..60f671902 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -1321,6 +1321,9 @@ init (xlator_t *this) conf->gfs_mgmt = &gd_brick_prog; strncpy (conf->workdir, workdir, PATH_MAX); + conf->snap_max_limit = GLUSTERD_SNAPS_MAX_LIMIT; + //TODO: read from saved value and update + synclock_init (&conf->big_lock); pthread_mutex_init (&conf->xprt_lock, NULL); INIT_LIST_HEAD (&conf->xprt_list); diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 10b338dda..1d5aa515b 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -52,6 +52,7 @@ "S56glusterd-geo-rep-create-post.sh" +#define GLUSTERD_SNAPS_MAX_LIMIT 256 #define GLUSTERD_SERVER_QUORUM "server" #define FMTSTR_CHECK_VOL_EXISTS "Volume %s does not exist" @@ -157,6 +158,7 @@ typedef struct { rpcsvc_t *uds_rpc; /* RPCSVC for the unix domain socket */ uint32_t base_port; struct list_head snap_cg; + uint64_t snap_max_limit; char *snap_bricks_directory; } glusterd_conf_t; @@ -276,6 +278,7 @@ struct glusterd_volinfo_ { int type; int brick_count; uint64_t snap_count; + uint64_t snap_max_limit; struct list_head vol_list; struct list_head bricks; struct list_head snaps; -- cgit