summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libglusterfs/src/dict.c190
-rw-r--r--libglusterfs/src/dict.h11
-rw-r--r--libglusterfs/src/glusterfs.h27
-rw-r--r--libglusterfs/src/libglusterfs.sym3
-rw-r--r--xlators/cluster/dht/src/dht-selfheal.c17
-rw-r--r--xlators/features/quota/src/quota-messages.h4
-rw-r--r--xlators/features/quota/src/quota.c31
-rw-r--r--xlators/storage/posix/src/posix-helpers.c4
8 files changed, 281 insertions, 6 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
index d1a64c4a3a2..0f9632160cc 100644
--- a/libglusterfs/src/dict.c
+++ b/libglusterfs/src/dict.c
@@ -2022,6 +2022,196 @@ err:
return ret;
}
+/*
+ * dict_check_flag can be used to check a one bit flag in an array of flags
+ * The flag argument indicates the bit position (within the array of bits).
+ * Currently limited to max of 256 flags for a key.
+ * return value,
+ * 1 : flag is set
+ * 0 : flag is not set
+ * <0: Error
+ */
+int
+dict_check_flag (dict_t *this, char *key, int flag)
+{
+ data_t *data = NULL;
+ int ret = -ENOENT;
+
+ ret = dict_get_with_ref (this, key, &data);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (BIT_VALUE((unsigned char *)(data->data), flag))
+ ret = 1;
+ else
+ ret = 0;
+
+ data_unref(data);
+ return ret;
+}
+
+/*
+ * _dict_modify_flag can be used to set/clear a bit flag in an array of flags
+ * flag: indicates the bit position. limited to max of DICT_MAX_FLAGS.
+ * op: Indicates operation DICT_FLAG_SET / DICT_FLAG_CLEAR
+ */
+static int
+_dict_modify_flag (dict_t *this, char *key, int flag, int op)
+{
+ data_t *data = NULL;
+ int ret = 0;
+ uint32_t hash = 0;
+ data_pair_t *pair = NULL;
+ char *ptr = NULL;
+ int hashval = 0;
+
+ if (!this || !key) {
+ gf_msg_callingfn ("dict", GF_LOG_WARNING, EINVAL,
+ LG_MSG_INVALID_ARG,
+ "dict OR key (%s) is NULL", key);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Using a size of 32 bytes to support max of 256
+ * flags in a single key. This should be suffcient.
+ */
+ GF_ASSERT(flag >= 0 && flag < DICT_MAX_FLAGS);
+
+ hash = SuperFastHash (key, strlen (key));
+ LOCK (&this->lock);
+ {
+ pair = dict_lookup_common (this, key, hash);
+
+ if (pair) {
+ data = pair->value;
+ if (op == DICT_FLAG_SET)
+ BIT_SET((unsigned char *)(data->data), flag);
+ else
+ BIT_CLEAR((unsigned char *)(data->data), flag);
+ ret = 0;
+ } else {
+ ptr = GF_CALLOC(1, DICT_MAX_FLAGS / 8,
+ gf_common_mt_char);
+ if (!ptr) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate flag bit array");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ data = data_from_dynptr(ptr, DICT_MAX_FLAGS / 8);
+
+ if (!data) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate data");
+ GF_FREE(ptr);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (op == DICT_FLAG_SET)
+ BIT_SET((unsigned char *)(data->data), flag);
+ else
+ BIT_CLEAR((unsigned char *)(data->data), flag);
+
+ if (this->free_pair_in_use) {
+ pair = mem_get0 (THIS->ctx->dict_pair_pool);
+ if (!pair) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate dict pair");
+ ret = -ENOMEM;
+ goto err;
+ }
+ } else {
+ pair = &this->free_pair;
+ this->free_pair_in_use = _gf_true;
+ }
+
+ pair->key = (char *)GF_CALLOC(1, strlen (key) + 1,
+ gf_common_mt_char);
+ if (!pair->key) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate dict pair");
+ ret = -ENOMEM;
+ goto err;
+ }
+ strcpy (pair->key, key);
+ pair->key_hash = hash;
+ pair->value = data_ref (data);
+
+ hashval = hash % this->hash_size;
+ pair->hash_next = this->members[hashval];
+ this->members[hashval] = pair;
+
+ pair->next = this->members_list;
+ pair->prev = NULL;
+ if (this->members_list)
+ this->members_list->prev = pair;
+ this->members_list = pair;
+ this->count++;
+
+
+ if (this->max_count < this->count)
+ this->max_count = this->count;
+ }
+ }
+
+ UNLOCK (&this->lock);
+ return 0;
+
+err:
+ UNLOCK (&this->lock);
+ if (pair) {
+ if (pair->key)
+ free(pair->key);
+
+ if (pair == &this->free_pair) {
+ this->free_pair_in_use = _gf_false;
+ } else {
+ mem_put (pair);
+ }
+ }
+
+ if (data)
+ data_destroy(data);
+
+
+ gf_msg("dict", GF_LOG_ERROR, EINVAL,
+ LG_MSG_DICT_SET_FAILED,
+ "unable to set key (%s) in dict ", key);
+
+ return ret;
+}
+
+/*
+ * Todo:
+ * Add below primitives as needed:
+ * dict_check_flags(this, key, flag...): variadic function to check
+ * multiple flags at a time.
+ * dict_set_flags(this, key, flag...): set multiple flags
+ * dict_clear_flags(this, key, flag...): reset multiple flags
+ */
+
+int
+dict_set_flag (dict_t *this, char *key, int flag)
+{
+ return _dict_modify_flag (this, key, flag, DICT_FLAG_SET);
+}
+
+int
+dict_clear_flag (dict_t *this, char *key, int flag)
+{
+ return _dict_modify_flag (this, key, flag, DICT_FLAG_CLEAR);
+}
+
+
int
dict_get_double (dict_t *this, char *key, double *val)
{
diff --git a/libglusterfs/src/dict.h b/libglusterfs/src/dict.h
index e481330d6b5..d0b05172c2e 100644
--- a/libglusterfs/src/dict.h
+++ b/libglusterfs/src/dict.h
@@ -60,10 +60,13 @@ typedef struct _data_pair data_pair_t;
\
} while (0)
-#define DICT_KEY_VALUE_MAX_SIZE 1048576
-
#define dict_foreach_inline(d, c) for (c = d->members_list; c; c = c->next)
+#define DICT_KEY_VALUE_MAX_SIZE 1048576
+#define DICT_MAX_FLAGS 256
+#define DICT_FLAG_SET 1
+#define DICT_FLAG_CLEAR 0
+
struct _data {
unsigned char is_static:1;
unsigned char is_const:1;
@@ -227,6 +230,10 @@ GF_MUST_CHECK int dict_set_uint32 (dict_t *this, char *key, uint32_t val);
GF_MUST_CHECK int dict_get_uint64 (dict_t *this, char *key, uint64_t *val);
GF_MUST_CHECK int dict_set_uint64 (dict_t *this, char *key, uint64_t val);
+GF_MUST_CHECK int dict_check_flag (dict_t *this, char *key, int flag);
+GF_MUST_CHECK int dict_set_flag (dict_t *this, char *key, int flag);
+GF_MUST_CHECK int dict_clear_flag (dict_t *this, char *key, int flag);
+
GF_MUST_CHECK int dict_get_double (dict_t *this, char *key, double *val);
GF_MUST_CHECK int dict_set_double (dict_t *this, char *key, double val);
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index 28666de3da4..84e33449dad 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -173,6 +173,33 @@
#define GLUSTERFS_VERSION_XCHG_KEY "glusterfs.version.xchg"
#define GLUSTERFS_INTERNAL_FOP_KEY "glusterfs-internal-fop"
+
+/* GlusterFS Internal FOP Indicator flags
+ * (To pass information on the context in which a paritcular
+ * fop is performed between translators)
+ * The presence of a particular flag must be treated as an
+ * indicator of the context, however the flag is added only in
+ * a scenario where there is a need for such context across translators.
+ * So it cannot be an absolute information on context.
+ */
+#define GF_INTERNAL_CTX_KEY "glusterfs.internal-ctx"
+
+/*
+ * Always append entries to end of the enum, do not delete entries.
+ * Currently dict_set_flag allows to set upto 256 flag, if the enum
+ * needs to grow beyond this dict_set_flag has to be changed accordingly
+ */
+enum gf_internal_fop_indicator {
+ GF_DHT_HEAL_DIR /* Index 0 in bit array*/
+};
+
+/* Todo:
+ * Add GF_FOP_LINK_FILE 0x2ULL
+ * address GLUSTERFS_MARKER_DONT_ACCOUNT_KEY and
+ * GLUSTERFS_INTERNAL_FOP_KEY with this flag
+ */
+
+
#define DHT_CHANGELOG_RENAME_OP_KEY "changelog.rename-op"
#define ZR_FILE_CONTENT_STR "glusterfs.file."
diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
index 6340bc8a3a2..1d21cfa8465 100644
--- a/libglusterfs/src/libglusterfs.sym
+++ b/libglusterfs/src/libglusterfs.sym
@@ -411,6 +411,9 @@ dict_set_static_ptr
dict_set_str
dict_set_uint32
dict_set_uint64
+dict_set_flag
+dict_clear_flag
+dict_check_flag
dict_unref
dict_unserialize
drop_token
diff --git a/xlators/cluster/dht/src/dht-selfheal.c b/xlators/cluster/dht/src/dht-selfheal.c
index d14020fabd0..4762f25067f 100644
--- a/xlators/cluster/dht/src/dht-selfheal.c
+++ b/xlators/cluster/dht/src/dht-selfheal.c
@@ -1411,10 +1411,25 @@ dht_selfheal_dir_mkdir_lookup_done (call_frame_t *frame, xlator_t *this)
dht_dir_set_heal_xattr (this, local, dict, local->xattr, NULL,
NULL);
- if (!dict)
+ if (!dict) {
gf_msg (this->name, GF_LOG_WARNING, 0,
DHT_MSG_DICT_SET_FAILED,
"dict is NULL, need to make sure gfids are same");
+ dict = dict_new ();
+ if (!dict)
+ return -1;
+ }
+ ret = dict_set_flag (dict, GF_INTERNAL_CTX_KEY, GF_DHT_HEAL_DIR);
+ if (ret) {
+ gf_msg (this->name, GF_LOG_ERROR, 0,
+ DHT_MSG_DICT_SET_FAILED,
+ "Failed to set dictionary value for"
+ " key = %s at path: %s",
+ GF_INTERNAL_CTX_KEY, loc->path);
+ /* We can still continue. As heal can still happen
+ * unless quota limits have reached for the dir.
+ */
+ }
cnt = layout->cnt;
for (i = 0; i < cnt; i++) {
diff --git a/xlators/features/quota/src/quota-messages.h b/xlators/features/quota/src/quota-messages.h
index 4292c5b4dcc..85f5abf7b29 100644
--- a/xlators/features/quota/src/quota-messages.h
+++ b/xlators/features/quota/src/quota-messages.h
@@ -46,7 +46,9 @@ GLFS_MSGID(QUOTA,
Q_MSG_INODE_CTX_GET_FAILED,
Q_MSG_INODE_CTX_SET_FAILED,
Q_MSG_LOOKUP_FAILED,
- Q_MSG_RPC_SUBMIT_FAILED
+ Q_MSG_RPC_SUBMIT_FAILED,
+ Q_MSG_ENFORCEMENT_SKIPPED,
+ Q_MSG_INTERNAL_FOP_KEY_MISSING
);
#endif /* !_QUOTA_MESSAGES_H_ */
diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c
index 068d2e8c1f1..6ef2e20cf61 100644
--- a/xlators/features/quota/src/quota.c
+++ b/xlators/features/quota/src/quota.c
@@ -1591,6 +1591,28 @@ out:
return ret;
}
+/*
+ * return _gf_true if enforcement is needed and _gf_false otherwise
+ */
+gf_boolean_t
+should_quota_enforce (xlator_t *this, dict_t *dict, glusterfs_fop_t fop)
+{
+ int ret = 0;
+
+ ret = dict_check_flag(dict, GF_INTERNAL_CTX_KEY, GF_DHT_HEAL_DIR);
+
+ if (fop == GF_FOP_MKDIR && ret == DICT_FLAG_SET) {
+ return _gf_false;
+ } else if (ret == -ENOENT) {
+ gf_msg (this->name, GF_LOG_DEBUG, EINVAL,
+ Q_MSG_INTERNAL_FOP_KEY_MISSING,
+ "No internal fop context present");
+ goto out;
+ }
+out:
+ return _gf_true;
+}
+
int32_t
quota_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
@@ -1965,7 +1987,6 @@ unwind:
return 0;
}
-
int32_t
quota_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
mode_t umask, dict_t *xdata)
@@ -1976,9 +1997,15 @@ quota_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
call_stub_t *stub = NULL;
priv = this->private;
-
WIND_IF_QUOTAOFF (priv->is_quota_on, off);
+ if (!should_quota_enforce(this, xdata, GF_FOP_MKDIR)) {
+ gf_msg (this->name, GF_LOG_DEBUG, 0,
+ Q_MSG_ENFORCEMENT_SKIPPED,
+ "Enforcement has been skipped(internal fop).");
+ goto off;
+ }
+
local = quota_local_new ();
if (local == NULL) {
op_errno = ENOMEM;
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
index 816fb3587d2..6d7d8c512db 100644
--- a/xlators/storage/posix/src/posix-helpers.c
+++ b/xlators/storage/posix/src/posix-helpers.c
@@ -1208,6 +1208,10 @@ posix_handle_pair (xlator_t *this, const char *real_path,
} else if (!strncmp(key, POSIX_ACL_ACCESS_XATTR, strlen(key))
&& stbuf && IS_DHT_LINKFILE_MODE (stbuf)) {
goto out;
+ } else if (!strncmp(key, GF_INTERNAL_CTX_KEY, strlen(key))) {
+ /* ignore this key value pair */
+ ret = 0;
+ goto out;
} else {
sys_ret = sys_lsetxattr (real_path, key, value->data,
value->len, flags);