diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-quota.c')
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-quota.c | 279 |
1 files changed, 267 insertions, 12 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index 1be768af..24bd41ad 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -671,14 +671,130 @@ out: return ret; } +static int +glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, + char *gfid_str, int opcode, char **op_errstr) +{ + int ret = -1; + int count = 0; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char buf[256] = {0,}; + int fd = -1; + FILE *conf_filep = NULL; + FILE *tmp_filep = NULL; + uuid_t gfid = {0,}; + uuid_t gfid_iter = {0,}; + gf_boolean_t found = _gf_false; + + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + uuid_parse (gfid_str, gfid); + + glusterd_store_create_quota_conf_sh_on_absence (volinfo); + + fd = gf_store_mkstemp (volinfo->quota_conf_shandle); + if (fd < 0) { + ret = -1; + goto out; + } + tmp_filep = fdopen (fd, "r+"); + + conf_filep = fopen (volinfo->quota_conf_shandle->path, "r"); + if (conf_filep == NULL) { + ret = -1; + goto out; + } + + while (fscanf (conf_filep, "%s", buf) != EOF) { + count++; + + uuid_parse (buf, gfid_iter); + + if (uuid_compare (gfid, gfid_iter)) + fprintf (tmp_filep, "%s\n", buf); + else + found = _gf_true; + } + + switch (opcode) { + case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: + /* + * 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 + * 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); + break; + + case GF_QUOTA_OPTION_TYPE_REMOVE: + /* + * count = 0 is not a valid scenario and must be treated + * as error. + * If count is non-zero and found is false, then it is + * an error. + * If count is non-zero and found is true, take no + * action, by virtue of which the gfid is as good as + * deleted from the store. + */ + if (count == 0) { + gf_asprintf (op_errstr, "Cannot remove limit on" + " %s. The quota configuration file" + " for volume %s is empty.", path, + volinfo->volname); + ret = -1; + 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; + } + } + break; + + default: + ret = 0; + break; + } + + ret = 0; +out: + if (conf_filep) + fclose (conf_filep); + if (tmp_filep) + fclose (tmp_filep); + + if (ret && (fd > 0)) + gf_store_unlink_tmppath (volinfo->quota_conf_shandle); + else if (!ret) + ret = gf_store_rename_tmppath (volinfo->quota_conf_shandle); + + return ret; +} + int32_t glusterd_quota_limit_usage (glusterd_volinfo_t *volinfo, dict_t *dict, - char **op_errstr) + int opcode, char **op_errstr) { int32_t ret = -1; char *path = NULL; char *hard_limit = NULL; char *soft_limit = NULL; + char *gfid_str = NULL; xlator_t *this = NULL; this = THIS; @@ -726,6 +842,19 @@ glusterd_quota_limit_usage (glusterd_volinfo_t *volinfo, dict_t *dict, if (ret) goto out; } + + ret = dict_get_str (dict, "gfid", &gfid_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid of path " + "%s", path); + goto out; + } + + ret = glusterd_store_quota_config (volinfo, path, gfid_str, opcode, + op_errstr); + if (ret) + goto out; + ret = 0; out: @@ -771,10 +900,11 @@ out: int32_t glusterd_quota_remove_limits (glusterd_volinfo_t *volinfo, dict_t *dict, - char **op_errstr) + int opcode, char **op_errstr) { int32_t ret = -1; char *path = NULL; + char *gfid_str = NULL; xlator_t *this = NULL; this = THIS; @@ -807,6 +937,20 @@ glusterd_quota_remove_limits (glusterd_volinfo_t *volinfo, dict_t *dict, if (ret) goto out; } + + ret = dict_get_str (dict, "gfid", &gfid_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid of path " + "%s", path); + goto out; + } + + ret = glusterd_store_quota_config (volinfo, path, gfid_str, opcode, + op_errstr); + if (ret) + goto out; + + ret = 0; out: @@ -939,12 +1083,12 @@ glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict) break; case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: - ret = glusterd_quota_limit_usage (volinfo, dict, + ret = glusterd_quota_limit_usage (volinfo, dict, type, op_errstr); goto out; case GF_QUOTA_OPTION_TYPE_REMOVE: - ret = glusterd_quota_remove_limits (volinfo, dict, + ret = glusterd_quota_remove_limits (volinfo, dict, type, op_errstr); goto out; @@ -1028,16 +1172,112 @@ out: return ret; } +/* + * glusterd_get_gfid_from_brick() fetches the 'trusted.gfid' attribute of @path + * from each brick in the backend and places the same in the rsp_dict with the + * keys being gfid0, gfid1, gfid2 and so on. The absence of @path in the backend + * is not treated as error. + */ +static int +glusterd_get_gfid_from_brick (dict_t *dict, glusterd_volinfo_t *volinfo, + dict_t *rsp_dict, char **op_errstr) +{ + int ret = -1; + int count = 0; + char *path = NULL; + char backend_path[PATH_MAX] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + char key[256] = {0,}; + char *gfid_str = NULL; + uuid_t gfid; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "path", &path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get path"); + goto out; + } + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + ret = glusterd_resolve_brick (brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK, + brickinfo->hostname, brickinfo->path); + goto out; + } + + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + if (volinfo->backend == GD_VOL_BK_BD) + continue; + + snprintf (backend_path, sizeof (backend_path), "%s%s", + brickinfo->path, path); + + ret = gf_lstat_dir (backend_path, NULL); + if (ret) { + gf_log (this->name, GF_LOG_INFO, "Failed to find " + "directory %s. Reason : %s", backend_path, + strerror (errno)); + ret = 0; + continue; + } + ret = sys_lgetxattr (backend_path, GFID_XATTR_KEY, gfid, 16); + if (ret < 0) { + gf_log (this->name, GF_LOG_INFO, "Failed to get " + "extended attribute %s for directory %s. " + "Reason : %s", GFID_XATTR_KEY, backend_path, + strerror (errno)); + ret = 0; + continue; + } + snprintf (key, sizeof (key), "gfid%d", count); + + gfid_str = gf_strdup (uuid_utoa (gfid)); + if (!gfid_str) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (rsp_dict, key, gfid_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to place " + "gfid of %s in dict", backend_path); + GF_FREE (gfid_str); + goto out; + } + count++; + } + + ret = dict_set_int32 (rsp_dict, "count", count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set count"); + goto out; + } + + ret = 0; +out: + return ret; +} + int -glusterd_op_stage_quota (dict_t *dict, char **op_errstr) +glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { - int ret = 0; - char *volname = NULL; - gf_boolean_t exists = _gf_false; - int type = 0; - dict_t *ctx = NULL; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; + int ret = 0; + char *volname = NULL; + gf_boolean_t exists = _gf_false; + int type = 0; + dict_t *ctx = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; this = THIS; GF_ASSERT (this); @@ -1059,6 +1299,12 @@ glusterd_op_stage_quota (dict_t *dict, char **op_errstr) ret = -1; goto out; } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname); + goto out; + } + ret = dict_get_int32 (dict, "type", &type); if (ret) { @@ -1089,6 +1335,15 @@ glusterd_op_stage_quota (dict_t *dict, char **op_errstr) } } + if (type == GF_QUOTA_OPTION_TYPE_LIMIT_USAGE || + type == GF_QUOTA_OPTION_TYPE_REMOVE) { + ret = glusterd_get_gfid_from_brick (dict, volinfo, rsp_dict, + op_errstr); + if (ret) + goto out; + } + ret = 0; + out: if (ret && op_errstr && *op_errstr) gf_log (this->name, GF_LOG_ERROR, "%s", *op_errstr); |