diff options
-rw-r--r-- | cli/src/cli-cmd-volume.c | 270 | ||||
-rw-r--r-- | cli/src/cli-rpc-ops.c | 9 | ||||
-rw-r--r-- | libglusterfs/src/common-utils.c | 16 | ||||
-rw-r--r-- | libglusterfs/src/common-utils.h | 2 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-quota.c | 184 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.c | 123 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.h | 7 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.c | 287 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.h | 6 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.h | 3 |
10 files changed, 742 insertions, 165 deletions
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 17663091..adad8442 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1096,16 +1096,193 @@ print_quota_list_header (void) } int -cli_get_soft_limit (call_frame_t *frame, cli_local_t *local, dict_t *options, - const char **words) +cli_get_soft_limit (dict_t *options, const char **words, dict_t *xdata) { - rpc_clnt_procedure_t *proc = NULL; - int ret = -1; + call_frame_t *frame = NULL; + cli_local_t *local = NULL; + rpc_clnt_procedure_t *proc = NULL; + char *default_sl = NULL; + char *default_sl_dup = NULL; + int ret = -1; + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) { + ret = -1; + goto out; + } + + //We need a ref on @options to prevent CLI_STACK_DESTROY + //from destroying it prematurely. + dict_ref (options); CLI_LOCAL_INIT (local, words, frame, options); proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA]; ret = proc->fn (frame, THIS, options); + ret = dict_get_str (options, "default-soft-limit", &default_sl); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get default soft limit"); + goto out; + } + + default_sl_dup = gf_strdup (default_sl); + if (!default_sl_dup) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (xdata, "default-soft-limit", default_sl_dup); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set default soft limit"); + GF_FREE (default_sl_dup); + goto out; + } + +out: + CLI_STACK_DESTROY (frame); + return ret; +} + +#define QUOTA_CONF_HEADER \ + "GlusterFS Quota conf | version: v%d.%d\n" +int +cli_cmd_quota_conf_skip_header (int fd) +{ + char buf[PATH_MAX] = {0,}; + + snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); + return gf_skip_header_section (fd, strlen (buf)); +} + +int +cli_cmd_quota_handle_list_all (const char **words, dict_t *options) +{ + int all_failed = 1; + int count = 0; + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + dict_t *xdata = NULL; + char *gfid_str = NULL; + char *volname = NULL; + char *volname_dup = NULL; + unsigned char buf[16] = {0}; + int fd = -1; + char quota_conf_file[PATH_MAX] = {0}; + + xdata = dict_new (); + if (!xdata) { + ret = -1; + goto out; + } + + ret = dict_get_str (options, "volname", &volname); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get volume name"); + goto out; + } + + ret = cli_get_soft_limit (options, words, xdata); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to fetch default " + "soft-limit"); + goto out; + } + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) { + ret = -1; + goto out; + } + + volname_dup = gf_strdup (volname); + if (!volname_dup) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (xdata, "volume-uuid", volname_dup); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set volume-uuid"); + GF_FREE (volname_dup); + goto out; + } + + //TODO: fix hardcoding; Need to perform an RPC call to glusterd + //to fetch working directory + sprintf (quota_conf_file, "/var/lib/glusterd/vols/%s/quota.conf", + volname); + fd = open (quota_conf_file, O_RDONLY); + if (fd == -1) { + //This may because no limits were yet set on the volume + gf_log ("cli", GF_LOG_TRACE, "Unable to open " + "quota.conf"); + ret = 0; + goto out; + } + + ret = cli_cmd_quota_conf_skip_header (fd); + if (ret) { + goto out; + } + CLI_LOCAL_INIT (local, words, frame, xdata); + proc = &cli_quotad_clnt.proctable[GF_AGGREGATOR_GETLIMIT]; + + print_quota_list_header (); + gfid_str = GF_CALLOC (1, gf_common_mt_char, 64); + if (!gfid_str) { + ret = -1; + goto out; + } + for (count = 0;; count++) { + ret = read (fd, (void*) buf, 16); + if (ret <= 0) { + //Finished reading all entries in the conf file + break; + } + if (ret < 16) { + //This should never happen. We must have a multiple of + //entry_sz bytes in our configuration file. + gf_log (THIS->name, GF_LOG_CRITICAL, "Quota " + "configuration store may be corrupt."); + goto out; + } + uuid_utoa_r (buf, gfid_str); + ret = dict_set_str (xdata, "gfid", gfid_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set gfid"); + goto out; + } + + ret = proc->fn (frame, THIS, xdata); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get quota " + "limits for %s", uuid_utoa ((unsigned char*)buf)); + } + + dict_del (xdata, "gfid"); + all_failed = all_failed && ret; + } + + if (count > 0) { + ret = all_failed? 0: -1; + } else { + ret = 0; + } +out: + if (count == 0) { + cli_out ("quota: No quota configured on volume %s", volname); + } + if (fd != -1) { + close (fd); + } + + GF_FREE (gfid_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Couldn't fetch quota limits " + "for even one of the directories configured"); + } + CLI_STACK_DESTROY (frame); return ret; } @@ -1124,26 +1301,11 @@ cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word, cli_local_t *local = NULL; int sent = 0; char *volname = NULL; - dict_t *xdata = NULL; - char buf[256] = {0}; - FILE *fp = NULL; const char *question = "Disabling quota will delete all the quota " "configuration. Do you want to continue?"; - proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA]; - if (proc == NULL) { - ret = -1; - goto out; - } - - frame = create_frame (THIS, THIS->ctx->pool); - if (!frame) { - ret = -1; - goto out; - } - + //parse **words into options dictionary ret = cli_cmd_quota_parse (words, wordcount, &options); - if (ret < 0) { cli_usage_out (word->pattern); parse_err = 1; @@ -1155,10 +1317,21 @@ cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word, gf_log ("cli", GF_LOG_ERROR, "Failed to get opcode"); goto out; } - if (type == GF_QUOTA_OPTION_TYPE_DISABLE) { + + //handle quota-disable and quota-list-all different from others + switch (type) { + case GF_QUOTA_OPTION_TYPE_DISABLE: answer = cli_cmd_get_confirmation (state, question); if (answer == GF_ANSWER_NO) goto out; + break; + case GF_QUOTA_OPTION_TYPE_LIST: + if (wordcount != 4) + break; + ret = cli_cmd_quota_handle_list_all (words, options); + goto out; + default: + break; } ret = dict_get_str (options, "volname", &volname); @@ -1166,59 +1339,29 @@ cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word, gf_log ("cli", GF_LOG_ERROR, "Failed to get volume name"); goto out; } - if (type == GF_QUOTA_OPTION_TYPE_LIST && wordcount == 4) { - ret = cli_get_soft_limit (frame, local, options, words); - if (ret) { - gf_log ("cli", GF_LOG_ERROR, "Failed to fetch default " - "soft-limit"); - goto out; - } - proc = &cli_quotad_clnt.proctable[GF_AGGREGATOR_GETLIMIT]; - xdata = dict_new (); - if (!xdata) { - ret = -1; - goto out; - } - ret = dict_set_str (xdata, "volume-uuid", volname); - if (ret) - goto out; - - char quota_conf_file[PATH_MAX] = {0}; - //TODO: fix hardcoding - sprintf (quota_conf_file, "/var/lib/glusterd/vols/%s/quota.conf", - volname); - fp = fopen (quota_conf_file, "r"); - if (!fp) { - gf_log ("cli", GF_LOG_ERROR, "Failed to open quota.conf"); - goto out; - } - - print_quota_list_header (); - while (fscanf (fp, "%s", buf) != EOF) { - - ret = dict_set_str (xdata, "gfid", buf); - if (ret) - goto out; - //Given the path, get the gfi - ret = proc->fn (frame, THIS, xdata); - dict_del (xdata, "gfid"); - - } - goto out; - } + //create auxillary mount need for quota commands that operate on path ret = cli_stage_quota_op (volname, type); if (ret) goto out; + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) { + ret = -1; + goto out; + } + CLI_LOCAL_INIT (local, words, frame, options); + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA]; + if (proc == NULL) { + ret = -1; + goto out; + } if (proc->fn) ret = proc->fn (frame, THIS, options); out: - if (fp) - fclose (fp); if (ret) { cli_cmd_sent_status_get (&sent); if (sent == 0 && parse_err == 0) @@ -1227,7 +1370,6 @@ out: } CLI_STACK_DESTROY (frame); - return ret; } diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 3edcd0d6..af228381 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -2593,8 +2593,8 @@ cli_quotad_getlimit_cbk (struct rpc_req *req, struct iovec *iov, "unserialize req-buffer to dictionary"); goto out; } + print_quota_list_from_quotad (frame, dict); } - print_quota_list_from_quotad (frame, dict); out: cli_cmd_broadcast_response (ret); @@ -2633,9 +2633,6 @@ cli_quotad_getlimit (call_frame_t *frame, xlator_t *this, void *data) (xdrproc_t) xdr_gf_cli_req); out: - if (ret) { - frame->local = NULL; - } gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; @@ -2717,7 +2714,7 @@ gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov, ret = dict_get_str (dict, "volname", &volname); if (ret) - gf_log (frame->this->name, GF_LOG_TRACE, + gf_log (frame->this->name, GF_LOG_ERROR, "failed to get volname"); ret = dict_get_str (dict, "default-soft-limit", &default_sl); @@ -2725,6 +2722,8 @@ gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov, gf_log (frame->this->name, GF_LOG_TRACE, "failed to get " "default soft limit"); + // default-soft-limit is part of rsp_dict only iff we sent + // GLUSTER_CLI_QUOTA with type being GF_QUOTA_OPTION_TYPE_LIST if (default_sl) { default_sl_dup = gf_strdup (default_sl); if (!default_sl_dup) { diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 061162f7..46fe6388 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -2940,3 +2940,19 @@ out: fclose (file); return running; } + +int +gf_skip_header_section (int fd, int header_len) +{ + int ret = -1; + + ret = lseek (fd, header_len, SEEK_SET); + if (ret == (off_t) -1) { + gf_log ("", GF_LOG_ERROR, "Failed to skip header " + "section"); + } else { + ret = 0; + } + + return ret; +} diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index 209e5025..6dde1aef 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -597,4 +597,6 @@ int gf_get_hard_limit (char *limit, char **hard_limit); gf_boolean_t gf_is_service_running (char *pidfile, int *pid); +int +gf_skip_header_section (int fd, int header_len); #endif /* _COMMON_UTILS_H */ diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index 24bd41ad..e67208cf 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -580,6 +580,8 @@ glusterd_quota_disable (glusterd_volinfo_t *volinfo, char **op_errstr) if (ret) goto out; + (void) glusterd_clean_up_quota_store (volinfo); + ret = 0; out: if (ret && op_errstr && !*op_errstr) @@ -671,6 +673,47 @@ out: return ret; } +#define QUOTA_CONF_HEADER \ + "GlusterFS Quota conf | version: v%d.%d\n" + +static int +glusterd_store_quota_conf_skip_header (xlator_t *this, int fd) +{ + char buf[PATH_MAX] = {0,}; + + snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); + return gf_skip_header_section (fd, strlen (buf)); +} + +static int +glusterd_store_quota_conf_stamp_header (xlator_t *this, int fd) +{ + char buf[PATH_MAX] = {0,}; + int buf_len = 0; + ssize_t ret = -1; + ssize_t written = 0; + + snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); + buf_len = strlen (buf); + for (written = 0; written != buf_len; written += ret) { + ret = write (fd, buf + written, buf_len - written); + if (ret == -1) { + goto out; + } + } + + ret = 0; +out: + return ret; +} + +static int +glusterd_update_quota_conf_version (glusterd_volinfo_t *volinfo) +{ + volinfo->quota_conf_version++; + return 0; +} + static int glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, char *gfid_str, int opcode, char **op_errstr) @@ -679,13 +722,13 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, int count = 0; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; - char buf[256] = {0,}; + unsigned char buf[16] = {0,}; int fd = -1; - FILE *conf_filep = NULL; - FILE *tmp_filep = NULL; + int conf_fd = -1; + size_t entry_sz = 16; uuid_t gfid = {0,}; - uuid_t gfid_iter = {0,}; gf_boolean_t found = _gf_false; + gf_boolean_t modified = _gf_false; this = THIS; @@ -702,23 +745,67 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, ret = -1; goto out; } - tmp_filep = fdopen (fd, "r+"); - conf_filep = fopen (volinfo->quota_conf_shandle->path, "r"); - if (conf_filep == NULL) { + conf_fd = open (volinfo->quota_conf_shandle->path, O_RDONLY); + if (conf_fd == -1) { ret = -1; goto out; } - while (fscanf (conf_filep, "%s", buf) != EOF) { - count++; - uuid_parse (buf, gfid_iter); + ret = glusterd_store_quota_conf_skip_header (this, conf_fd); + if (ret) { + goto out; + } - if (uuid_compare (gfid, gfid_iter)) - fprintf (tmp_filep, "%s\n", buf); - else + ret = glusterd_store_quota_conf_stamp_header (this, fd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to add header to tmp " + "file."); + goto out; + } + //gfid is stored as 16 bytes of 'raw' data + entry_sz = 16; + for (;;) { + ret = read (conf_fd, (void*)&buf, entry_sz) ; + if (ret <= 0) { + //Finished reading all entries in the conf file + break; + } + if (ret != 16) { + //This should never happen. We must have a multiple of + //entry_sz bytes in our configuration file. + gf_log (this->name, GF_LOG_CRITICAL, "Quota " + "configuration store may be corrupt."); + ret = -1; + goto out; + } + count++; + if (uuid_compare (gfid, buf)) { + /*If the gfids don't match, write @buf into tmp file. */ + ret = write (fd, (void*) buf, entry_sz); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "write %s into quota configuration.", + uuid_utoa (buf)); + goto out; + } + } else { + /*If a match is found, write @buf into tmp file for + * limit-usage only. + */ + if (opcode == GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) { + ret = write (fd, (void *) buf, entry_sz); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to write %s into quota " + "configuration.", + uuid_utoa (buf)); + goto out; + } + } found = _gf_true; + } } switch (opcode) { @@ -727,15 +814,24 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, * count = 0 implies that the conf file is empty. * In this case, we directly go ahead and write gfid_str * into the tmp file. - * If count is non-zero and found is false, then we - * append gfid_str to the end of the file. - * If count is non-zero and found is true, then again + * If count is non-zero and found is false, limit is + * being set on a gfid for the first time. So * append gfid_str to the end of the file. - * - * In short, in all of the above cases, append gfid_str - * to the end of the file. */ - fprintf (tmp_filep, "%s\n", gfid_str); + if ((count == 0) || + ((count > 0) && (found == _gf_false))) { + memcpy (buf, gfid, 16); + ret = write (fd, (void *) buf, entry_sz); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to write %s into quota " + "configuration.", + uuid_utoa (buf)); + goto out; + } + modified = _gf_true; + } + break; case GF_QUOTA_OPTION_TYPE_REMOVE: @@ -757,12 +853,15 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, goto out; } else { if (!found) { - gf_asprintf (op_errstr, "Error. gfid %s for " - "path %s not found in store", - gfid_str, path); - ret = -1; - goto out; + gf_asprintf (op_errstr, "Error. gfid %s" + " for path %s not found in" + " store", gfid_str, path); + ret = -1; + goto out; + } else { + modified = _gf_true; } + } break; @@ -771,17 +870,40 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, break; } + if (modified) + glusterd_update_quota_conf_version (volinfo); + ret = 0; out: - if (conf_filep) - fclose (conf_filep); - if (tmp_filep) - fclose (tmp_filep); + if (conf_fd != -1) { + close (conf_fd); + } + + if (fd != -1) { + close (fd); + } - if (ret && (fd > 0)) + if (ret && (fd > 0)) { gf_store_unlink_tmppath (volinfo->quota_conf_shandle); - else if (!ret) + } else if (!ret) { ret = gf_store_rename_tmppath (volinfo->quota_conf_shandle); + if (modified) { + ret = glusterd_compute_cksum (volinfo, _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "compute cksum for quota conf file"); + goto out; + } + + ret = glusterd_store_save_quota_version_and_cksum + (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "store quota version and cksum"); + goto out; + } + } + } return ret; } diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c index b9f4792d..db0829bb 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.c +++ b/xlators/mgmt/glusterd/src/glusterd-store.c @@ -1099,7 +1099,7 @@ glusterd_store_volinfo (glusterd_volinfo_t *volinfo, glusterd_volinfo_ver_ac_t a goto out; //checksum should be computed at the end - ret = glusterd_volume_compute_cksum (volinfo); + ret = glusterd_compute_cksum (volinfo, _gf_false); if (ret) goto out; @@ -1977,7 +1977,23 @@ glusterd_store_retrieve_volume (char *volname) if (ret) goto out; - ret = glusterd_volume_compute_cksum (volinfo); + ret = glusterd_compute_cksum (volinfo, _gf_false); + if (ret) + goto out; + + ret = glusterd_store_retrieve_quota_version (volinfo); + if (ret) + goto out; + + ret = glusterd_store_create_quota_conf_sh_on_absence (volinfo); + if (ret) + goto out; + + ret = glusterd_compute_cksum (volinfo, _gf_true); + if (ret) + goto out; + + ret = glusterd_store_save_quota_version_and_cksum (volinfo); if (ret) goto out; @@ -2572,3 +2588,106 @@ out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } + +int +glusterd_store_retrieve_quota_version (glusterd_volinfo_t *volinfo) +{ + int ret = -1; + uint32_t version = 0; + char cksum_path[PATH_MAX] = {0,}; + char path[PATH_MAX] = {0,}; + char *version_str = NULL; + char *tmp = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + gf_store_handle_t *handle = NULL; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); + snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); + + ret = gf_store_handle_new (cksum_path, &handle); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get store handle " + "for %s", cksum_path); + goto out; + } + + ret = gf_store_retrieve_value (handle, "version", &version_str); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "Version absent"); + ret = 0; + goto out; + } + + version = strtoul (version_str, &tmp, 10); + if (version < 0) { + gf_log (this->name, GF_LOG_DEBUG, "Invalid version number"); + goto out; + } + volinfo->quota_conf_version = version; + ret = 0; + +out: + if (version_str) + GF_FREE (version_str); + gf_store_handle_destroy (handle); + return ret; +} + +int +glusterd_store_save_quota_version_and_cksum (glusterd_volinfo_t *volinfo) +{ + int ret = -1; + char cksum_path[PATH_MAX] = {0,}; + char path[PATH_MAX] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char buf[256] = {0,}; + int fd = -1; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); + snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); + + fd = open (cksum_path, O_RDWR | O_APPEND | O_CREAT| O_TRUNC, 0600); + + if (-1 == fd) { + gf_log (this->name, GF_LOG_ERROR, "Unable to open %s," + "Reason: %s", cksum_path, strerror (errno)); + ret = -1; + goto out; + } + + snprintf (buf, sizeof (buf)-1, "%u", volinfo->quota_conf_cksum); + ret = gf_store_save_value (fd, "cksum", buf); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to store cksum"); + goto out; + } + + memset (buf, 0, sizeof (buf)); + snprintf (buf, sizeof (buf)-1, "%u", volinfo->quota_conf_version); + ret = gf_store_save_value (fd, "version", buf); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to store version"); + goto out; + } + + ret = 0; + +out: + if (fd != -1) + close (fd); + return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-store.h b/xlators/mgmt/glusterd/src/glusterd-store.h index 2dc05157..20cbf659 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.h +++ b/xlators/mgmt/glusterd/src/glusterd-store.h @@ -127,4 +127,11 @@ glusterd_store_options (xlator_t *this, dict_t *opts); int32_t glusterd_store_create_quota_conf_sh_on_absence (glusterd_volinfo_t *volinfo); + +int +glusterd_store_retrieve_quota_version (glusterd_volinfo_t *volinfo); + +int +glusterd_store_save_quota_version_and_cksum (glusterd_volinfo_t *volinfo); + #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 000a6b10..66f4c971 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -1538,89 +1538,85 @@ glusterd_sort_and_redirect (const char *src_filepath, int dest_fd) } int -glusterd_volume_compute_cksum (glusterd_volinfo_t *volinfo) -{ - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - char path[PATH_MAX] = {0,}; - char cksum_path[PATH_MAX] = {0,}; - char filepath[PATH_MAX] = {0,}; - int fd = -1; - uint32_t cksum = 0; - char buf[4096] = {0,}; +glusterd_volume_compute_cksum (glusterd_volinfo_t *volinfo, char *cksum_path, + char *filepath, gf_boolean_t is_quota_conf, + uint32_t *cs) +{ + int32_t ret = -1; + uint32_t cksum = 0; + int fd = -1; + int sort_fd = 0; char sort_filepath[PATH_MAX] = {0}; - gf_boolean_t unlink_sortfile = _gf_false; - int sort_fd = 0; - xlator_t *this = NULL; + char *cksum_path_final = NULL; + char buf[4096] = {0,}; + gf_boolean_t unlink_sortfile = _gf_false; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; GF_ASSERT (volinfo); this = THIS; priv = THIS->private; GF_ASSERT (priv); - GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv); - - snprintf (cksum_path, sizeof (cksum_path), "%s/%s", - path, GLUSTERD_CKSUM_FILE); - fd = open (cksum_path, O_RDWR | O_APPEND | O_CREAT| O_TRUNC, 0600); if (-1 == fd) { - gf_log (this->name, GF_LOG_ERROR, "Unable to open %s, errno: %d", - cksum_path, errno); + gf_log (this->name, GF_LOG_ERROR, "Unable to open %s," + " errno: %d", cksum_path, errno); ret = -1; goto out; } - snprintf (filepath, sizeof (filepath), "%s/%s", path, - GLUSTERD_VOLUME_INFO_FILE); - snprintf (sort_filepath, sizeof (sort_filepath), "/tmp/%s.XXXXXX", - volinfo->volname); + if (!is_quota_conf) { + snprintf (sort_filepath, sizeof (sort_filepath), + "/tmp/%s.XXXXXX", volinfo->volname); - sort_fd = mkstemp (sort_filepath); - if (sort_fd < 0) { - gf_log (this->name, GF_LOG_ERROR, "Could not generate temp " - "file, reason: %s for volume: %s", strerror (errno), - volinfo->volname); - goto out; - } else { - unlink_sortfile = _gf_true; - } + sort_fd = mkstemp (sort_filepath); + if (sort_fd < 0) { + gf_log (this->name, GF_LOG_ERROR, "Could not generate " + "temp file, reason: %s for volume: %s", + strerror (errno), volinfo->volname); + goto out; + } else { + unlink_sortfile = _gf_true; + } - /* sort the info file, result in sort_filepath */ + /* sort the info file, result in sort_filepath */ - ret = glusterd_sort_and_redirect (filepath, sort_fd); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "sorting info file failed"); - goto out; - } + ret = glusterd_sort_and_redirect (filepath, sort_fd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "sorting info file " + "failed"); + goto out; + } - ret = close (sort_fd); - if (ret) - goto out; + ret = close (sort_fd); + if (ret) + goto out; + } - ret = get_checksum_for_path (sort_filepath, &cksum); + cksum_path_final = is_quota_conf ? filepath : sort_filepath; + ret = get_checksum_for_path (cksum_path_final, &cksum); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to get checksum" - " for path: %s", sort_filepath); + gf_log (this->name, GF_LOG_ERROR, "unable to get " + "checksum for path: %s", cksum_path_final); goto out; } - - snprintf (buf, sizeof (buf), "%s=%u\n", "info", cksum); - ret = write (fd, buf, strlen (buf)); - - if (ret <= 0) { - ret = -1; - goto out; + if (!is_quota_conf) { + snprintf (buf, sizeof (buf), "%s=%u\n", "info", cksum); + ret = write (fd, buf, strlen (buf)); + if (ret <= 0) { + ret = -1; + goto out; + } } ret = get_checksum_for_file (fd, &cksum); - if (ret) goto out; - volinfo->cksum = cksum; + *cs = cksum; out: if (fd > 0) @@ -1632,6 +1628,54 @@ out: return ret; } +int glusterd_compute_cksum (glusterd_volinfo_t *volinfo, + gf_boolean_t is_quota_conf) +{ + int ret = -1; + uint32_t cs = 0; + char cksum_path[PATH_MAX] = {0,}; + char path[PATH_MAX] = {0,}; + char filepath[PATH_MAX] = {0,}; + glusterd_conf_t *conf = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); + + if (is_quota_conf) { + snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); + snprintf (filepath, sizeof (filepath), "%s/%s", path, + GLUSTERD_VOLUME_QUOTA_CONFIG); + } else { + snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, + GLUSTERD_CKSUM_FILE); + snprintf (filepath, sizeof (filepath), "%s/%s", path, + GLUSTERD_VOLUME_INFO_FILE); + } + + ret = glusterd_volume_compute_cksum (volinfo, cksum_path, filepath, + is_quota_conf, &cs); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to compute checksum " + "for volume %s", volinfo->volname); + goto out; + } + + if (is_quota_conf) + volinfo->quota_conf_cksum = cs; + else + volinfo->cksum = cs; + + ret = 0; +out: + return ret; +} + int _add_dict_to_prdict (dict_t *this, char *key, data_t *value, void *data) { @@ -1977,6 +2021,18 @@ glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t* load, if (ret) goto out; + snprintf (key, sizeof(key)-1, "volume%d.quota-cksum", vol_idx); + key[sizeof(key)-1] = '\0'; + ret = dict_set_uint32 (load, key, volinfo->quota_conf_cksum); + if (ret) + goto out; + + snprintf (key, sizeof(key)-1, "volume%d.quota-version", vol_idx); + key[sizeof(key)-1] = '\0'; + ret = dict_set_uint32 (load, key, volinfo->quota_conf_version); + if (ret) + goto out; + ret = 0; out: if (fp) @@ -2049,11 +2105,17 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, glusterd_volinfo_t *volinfo = NULL; char *volname = NULL; uint32_t cksum = 0; + uint32_t quota_cksum = 0; + uint32_t quota_version = 0; int32_t version = 0; + xlator_t *this = NULL; GF_ASSERT (vols); GF_ASSERT (status); + this = THIS; + GF_ASSERT (this); + snprintf (key, sizeof (key), "volume%d.name", count); ret = dict_get_str (vols, key, &volname); if (ret) @@ -2076,7 +2138,7 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, if (version > volinfo->version) { //Mismatch detected ret = 0; - gf_log ("", GF_LOG_ERROR, "Version of volume %s differ." + gf_log (this->name, GF_LOG_ERROR, "Version of volume %s differ." "local version = %d, remote version = %d on peer %s", volinfo->volname, volinfo->version, version, hostname); *status = GLUSTERD_VOL_COMP_UPDATE_REQ; @@ -2096,17 +2158,66 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, if (cksum != volinfo->cksum) { ret = 0; - gf_log ("", GF_LOG_ERROR, "Cksums of volume %s differ." + gf_log (this->name, GF_LOG_ERROR, "Cksums of volume %s differ." " local cksum = %u, remote cksum = %u on peer %s", volinfo->volname, volinfo->cksum, cksum, hostname); *status = GLUSTERD_VOL_COMP_RJT; goto out; } + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.quota-version", count); + ret = dict_get_uint32 (vols, key, "a_version); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "quota-version key absent for" + " volume %s in peer %s's response", volinfo->volname, + hostname); + ret = 0; + } else { + if (quota_version > volinfo->quota_conf_version) { + //Mismatch detected + ret = 0; + gf_log (this->name, GF_LOG_ERROR, "Quota configuration " + "versions of volume %s differ. " + "local version = %d, remote version = %d " + "on peer %s", volinfo->volname, + volinfo->quota_conf_version, quota_version, + hostname); + *status = GLUSTERD_VOL_COMP_UPDATE_REQ; + goto out; + } else if (quota_version < volinfo->quota_conf_version) { + *status = GLUSTERD_VOL_COMP_SCS; + goto out; + } + } + + //Now, versions are same, compare cksums. + // + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.quota-cksum", count); + ret = dict_get_uint32 (vols, key, "a_cksum); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "quota checksum absent for " + "volume %s in peer %s's response", volinfo->volname, + hostname); + ret = 0; + } else { + if (quota_cksum != volinfo->quota_conf_cksum) { + ret = 0; + gf_log (this->name, GF_LOG_ERROR, "Cksums of quota " + "configurations of volume %s differ. " + "local cksum = %u, remote cksum = %u on " + "peer %s", volinfo->volname, + volinfo->quota_conf_cksum, quota_cksum, + hostname); + *status = GLUSTERD_VOL_COMP_RJT; + goto out; + } + } *status = GLUSTERD_VOL_COMP_SCS; out: - gf_log ("", GF_LOG_DEBUG, "Returning with ret: %d, status: %d", + gf_log (this->name, GF_LOG_DEBUG, "Returning with ret: %d, status: %d", ret, *status); return ret; } @@ -2565,8 +2676,10 @@ glusterd_import_quota_conf (dict_t *vols, int vol_idx, char key[PATH_MAX] = {0}; char *gfid_str = NULL; - if (!glusterd_is_volume_quota_enabled (new_volinfo)) + if (!glusterd_is_volume_quota_enabled (new_volinfo)) { + (void) glusterd_clean_up_quota_store (new_volinfo); return 0; + } ret = glusterd_store_create_quota_conf_sh_on_absence (new_volinfo); if (ret) @@ -2583,6 +2696,19 @@ glusterd_import_quota_conf (dict_t *vols, int vol_idx, goto out; } + snprintf (key, sizeof (key)-1, "volume%d.quota-cksum", vol_idx); + key[sizeof(key)-1] = '\0'; + ret = dict_get_uint32 (vols, key, &new_volinfo->quota_conf_cksum); + if (ret) + gf_log (THIS->name, GF_LOG_DEBUG, "Failed to get quota cksum"); + + snprintf (key, sizeof (key)-1, "volume%d.quota-version", vol_idx); + key[sizeof(key)-1] = '\0'; + ret = dict_get_uint32 (vols, key, &new_volinfo->quota_conf_version); + if (ret) + gf_log (THIS->name, GF_LOG_DEBUG, "Failed to get quota " + "version"); + snprintf (key, sizeof (key)-1, "volume%d.gfid-count", vol_idx); key[sizeof(key)-1] = '\0'; ret = dict_get_int32 (vols, key, &gfid_count); @@ -2608,13 +2734,20 @@ glusterd_import_quota_conf (dict_t *vols, int vol_idx, ret = gf_store_rename_tmppath (new_volinfo->quota_conf_shandle); -out: - if (tmp_fp) { - fclose (tmp_fp); + ret = 0; - } else if (fd >= 0) { +out: + if (fd != -1) close (fd); + if (!ret) { + ret = glusterd_compute_cksum (new_volinfo, _gf_true); + if (ret) + goto out; + + ret = glusterd_store_save_quota_version_and_cksum (new_volinfo); + if (ret) + goto out; } if (ret && (fd > 0)) { @@ -8126,3 +8259,33 @@ glusterd_validate_and_set_gfid (dict_t *op_ctx, dict_t *req_dict, out: return ret; } + +void +glusterd_clean_up_quota_store (glusterd_volinfo_t *volinfo) +{ + char voldir[PATH_MAX] = {0,}; + char quota_confpath[PATH_MAX] = {0,}; + char cksum_path[PATH_MAX] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + GLUSTERD_GET_VOLUME_DIR (voldir, volinfo, conf); + + snprintf (quota_confpath, sizeof (quota_confpath), "%s/%s", voldir, + GLUSTERD_VOLUME_QUOTA_CONFIG); + snprintf (cksum_path, sizeof (cksum_path), "%s/%s", voldir, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); + + unlink (quota_confpath); + unlink (cksum_path); + + gf_store_handle_destroy (volinfo->quota_conf_shandle); + volinfo->quota_conf_shandle = NULL; + volinfo->quota_conf_version = 0; + +} diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index 1074c46d..3be5458d 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -158,7 +158,8 @@ int32_t glusterd_compare_friend_data (dict_t *vols, int32_t *status, char *hostname); int -glusterd_volume_compute_cksum (glusterd_volinfo_t *volinfo); +glusterd_compute_cksum (glusterd_volinfo_t *volinfo, + gf_boolean_t is_quota_conf); void glusterd_get_nodesvc_volfile (char *server, char *workdir, @@ -593,4 +594,7 @@ glusterd_all_volumes_with_quota_stopped (); int glusterd_reconfigure_quotad (); + +void +glusterd_clean_up_quota_store (glusterd_volinfo_t *volinfo); #endif diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 516409dc..3fb303ca 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -285,7 +285,9 @@ struct glusterd_volinfo_ { glusterd_replace_brick_t rep_brick; int version; + uint32_t quota_conf_version; uint32_t cksum; + uint32_t quota_conf_cksum; gf_transport_type transport_type; gf_transport_type nfs_transport_type; @@ -344,6 +346,7 @@ enum glusterd_vol_comp_status_ { #define GLUSTERD_VOLUME_RBSTATE_FILE "rbstate" #define GLUSTERD_BRICK_INFO_DIR "bricks" #define GLUSTERD_CKSUM_FILE "cksum" +#define GLUSTERD_VOL_QUOTA_CKSUM_FILE "quota.cksum" #define GLUSTERD_TRASH "trash" #define GLUSTERD_NODE_STATE_FILE "node_state.info" |