summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt/glusterd/src/glusterd-quota.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-quota.c')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-quota.c279
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);