summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cli/src/cli-rpc-ops.c65
-rw-r--r--libglusterfs/src/glusterfs.h3
-rw-r--r--libglusterfs/src/syncop.c36
-rw-r--r--libglusterfs/src/syncop.h4
-rw-r--r--libglusterfs/src/xlator.c42
-rw-r--r--libglusterfs/src/xlator.h1
-rw-r--r--xlators/features/marker/src/marker-mem-types.h2
-rw-r--r--xlators/features/marker/src/marker-quota-helper.c50
-rw-r--r--xlators/features/marker/src/marker-quota-helper.h2
-rw-r--r--xlators/features/marker/src/marker-quota.c1723
-rw-r--r--xlators/features/marker/src/marker-quota.h62
-rw-r--r--xlators/features/marker/src/marker.c67
12 files changed, 1788 insertions, 269 deletions
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index b2964b68ff6..8ea43f824bc 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -2413,23 +2413,29 @@ static int
print_quota_list_output (cli_local_t *local, char *mountdir,
char *default_sl, char *path)
{
- int64_t used_space = 0;
- int64_t avail = 0;
- char *used_str = NULL;
- char *avail_str = NULL;
- int ret = -1;
- char *sl_final = NULL;
- char *hl_str = NULL;
- double sl_num = 0;
- gf_boolean_t sl = _gf_false;
- gf_boolean_t hl = _gf_false;
- char percent_str[20] = {0};
+ int64_t avail = 0;
+ char *used_str = NULL;
+ char *avail_str = NULL;
+ int ret = -1;
+ char *sl_final = NULL;
+ char *hl_str = NULL;
+ double sl_num = 0;
+ gf_boolean_t sl = _gf_false;
+ gf_boolean_t hl = _gf_false;
+ char percent_str[20] = {0};
+ ssize_t xattr_size = 0;
struct quota_limit {
int64_t hl;
int64_t sl;
} __attribute__ ((__packed__)) existing_limits;
+ struct quota_meta {
+ int64_t size;
+ int64_t file_count;
+ int64_t dir_count;
+ } __attribute__ ((__packed__)) used_space;
+
ret = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.limit-set",
(void *)&existing_limits,
sizeof (existing_limits));
@@ -2490,10 +2496,26 @@ print_quota_list_output (cli_local_t *local, char *mountdir,
sl_final = percent_str;
}
- ret = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.size",
- &used_space, sizeof (used_space));
+ used_space.size = used_space.file_count = used_space.dir_count = 0;
+ xattr_size = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.size",
+ NULL, 0);
+ if (xattr_size > sizeof (int64_t)) {
+ ret = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.size",
+ &used_space, sizeof (used_space));
+ } else if (xattr_size > 0) {
+ /* This is for compatibility.
+ * Older version had only file usage
+ */
+ ret = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.size",
+ &(used_space.size), sizeof (used_space.size));
+ } else {
+ ret = -1;
+ }
if (ret < 0) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get quota size "
+ "on path %s: %s", mountdir, strerror (errno));
+
if (global_state->mode & GLUSTER_MODE_XML) {
ret = cli_quota_xml_output (local, path, hl_str,
sl_final, "N/A",
@@ -2510,14 +2532,16 @@ print_quota_list_output (cli_local_t *local, char *mountdir,
"N/A", "N/A", "N/A", "N/A");
}
} else {
- used_space = ntoh64 (used_space);
+ used_space.size = ntoh64 (used_space.size);
+ used_space.file_count = ntoh64 (used_space.file_count);
+ used_space.dir_count = ntoh64 (used_space.dir_count);
- used_str = gf_uint64_2human_readable (used_space);
+ used_str = gf_uint64_2human_readable (used_space.size);
- if (existing_limits.hl > used_space) {
- avail = existing_limits.hl - used_space;
+ if (existing_limits.hl > used_space.size) {
+ avail = existing_limits.hl - used_space.size;
hl = _gf_false;
- if (used_space > sl_num)
+ if (used_space.size > sl_num)
sl = _gf_true;
else
sl = _gf_false;
@@ -2544,8 +2568,9 @@ print_quota_list_output (cli_local_t *local, char *mountdir,
if (used_str == NULL) {
cli_out ("%-40s %7s %9s %11"PRIu64
"%9"PRIu64" %15s %18s", path, hl_str,
- sl_final, used_space, avail, sl? "Yes" : "No",
- hl? "Yes" : "No");
+ sl_final, used_space.size, avail,
+ sl ? "Yes" : "No",
+ hl ? "Yes" : "No");
} else {
cli_out ("%-40s %7s %9s %11s %7s %15s %20s", path, hl_str,
sl_final, used_str, avail_str, sl? "Yes" : "No",
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index 8d7659b5015..a810f3a81f0 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -128,11 +128,12 @@
#define GLUSTERFS_POSIXLK_COUNT "glusterfs.posixlk-count"
#define GLUSTERFS_PARENT_ENTRYLK "glusterfs.parent-entrylk"
#define GLUSTERFS_INODELK_DOM_COUNT "glusterfs.inodelk-dom-count"
-#define QUOTA_SIZE_KEY "trusted.glusterfs.quota.size"
#define GFID_TO_PATH_KEY "glusterfs.gfid2path"
#define GF_XATTR_STIME_PATTERN "trusted.glusterfs.*.stime"
#define GF_XATTR_TRIGGER_SYNC "glusterfs.geo-rep.trigger-sync"
+#define QUOTA_SIZE_KEY "trusted.glusterfs.quota.size"
+
/* Index xlator related */
#define GF_XATTROP_INDEX_GFID "glusterfs.xattrop_index_gfid"
#define GF_XATTROP_INDEX_COUNT "glusterfs.xattrop_index_count"
diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c
index e3321cf6ddb..e241e2c1ee0 100644
--- a/libglusterfs/src/syncop.c
+++ b/libglusterfs/src/syncop.c
@@ -2537,3 +2537,39 @@ syncop_inodelk (xlator_t *subvol, const char *volume, loc_t *loc, int32_t cmd,
return args.op_ret;
}
+
+int32_t
+syncop_xattrop_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, dict_t *dict,
+ dict_t *xdata)
+{
+ struct syncargs *args = NULL;
+
+ args = cookie;
+
+ args->op_ret = op_ret;
+ args->op_errno = op_errno;
+
+ if (xdata)
+ args->xdata = dict_ref (xdata);
+
+ __wake (args);
+
+ return 0;
+
+}
+
+int
+syncop_xattrop (xlator_t *subvol, loc_t *loc, gf_xattrop_flags_t flags,
+ dict_t *dict, dict_t *xdata)
+{
+ struct syncargs args = {0, };
+
+ SYNCOP (subvol, (&args), syncop_xattrop_cbk, subvol->fops->xattrop,
+ loc, flags, dict, xdata);
+
+ if (args.op_ret < 0)
+ return -args.op_errno;
+
+ return args.op_ret;
+}
diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h
index 7f8ec7345b0..a9244a51552 100644
--- a/libglusterfs/src/syncop.h
+++ b/libglusterfs/src/syncop.h
@@ -439,4 +439,8 @@ syncop_inodelk (xlator_t *subvol, const char *volume, loc_t *loc, int32_t cmd,
int
syncop_ipc (xlator_t *subvol, int op, dict_t *xdata_in, dict_t **xdata_out);
+int
+syncop_xattrop (xlator_t *subvol, loc_t *loc, gf_xattrop_flags_t flags,
+ dict_t *dict, dict_t *xdata);
+
#endif /* _SYNCOP_H */
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c
index 49af7d2e0e6..cc4726e0ea5 100644
--- a/libglusterfs/src/xlator.c
+++ b/libglusterfs/src/xlator.c
@@ -860,9 +860,51 @@ loc_is_root (loc_t *loc)
} else if (loc && loc->inode && __is_root_gfid (loc->inode->gfid)) {
return _gf_true;
}
+
return _gf_false;
}
+int32_t
+loc_build_child (loc_t *child, loc_t *parent, char *name)
+{
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("xlator", child, out);
+ GF_VALIDATE_OR_GOTO ("xlator", parent, out);
+ GF_VALIDATE_OR_GOTO ("xlator", name, out);
+
+ loc_gfid (parent, child->pargfid);
+
+ if (strcmp (parent->path, "/") == 0)
+ ret = gf_asprintf ((char **)&child->path, "/%s", name);
+ else
+ ret = gf_asprintf ((char **)&child->path, "%s/%s", parent->path,
+ name);
+
+ if (ret < 0 || !child->path) {
+ ret = -1;
+ goto out;
+ }
+
+ child->name = strrchr (child->path, '/') + 1;
+
+ child->parent = inode_ref (parent->inode);
+ child->inode = inode_new (parent->inode->table);
+
+ if (!child->inode) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if ((ret < 0) && child)
+ loc_wipe (child);
+
+ return ret;
+}
+
int
xlator_destroy (xlator_t *xl)
{
diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h
index e953ec04372..733f6cf47ab 100644
--- a/libglusterfs/src/xlator.h
+++ b/libglusterfs/src/xlator.h
@@ -960,6 +960,7 @@ int loc_path (loc_t *loc, const char *bname);
void loc_gfid (loc_t *loc, uuid_t gfid);
char* loc_gfid_utoa (loc_t *loc);
gf_boolean_t loc_is_root (loc_t *loc);
+int32_t loc_build_child (loc_t *child, loc_t *parent, char *name);
int xlator_mem_acct_init (xlator_t *xl, int num_types);
int is_gf_log_command (xlator_t *trans, const char *name, char *value);
int glusterd_check_log_level (const char *value);
diff --git a/xlators/features/marker/src/marker-mem-types.h b/xlators/features/marker/src/marker-mem-types.h
index 1f74d504897..dc5ad16ed76 100644
--- a/xlators/features/marker/src/marker-mem-types.h
+++ b/xlators/features/marker/src/marker-mem-types.h
@@ -20,6 +20,8 @@ enum gf_marker_mem_types_ {
gf_marker_mt_quota_inode_ctx_t,
gf_marker_mt_marker_inode_ctx_t,
gf_marker_mt_inode_contribution_t,
+ gf_marker_mt_quota_meta_t,
+ gf_marker_mt_quota_synctask_t,
gf_marker_mt_end
};
#endif
diff --git a/xlators/features/marker/src/marker-quota-helper.c b/xlators/features/marker/src/marker-quota-helper.c
index ec0d83316c7..cdc2475c3e8 100644
--- a/xlators/features/marker/src/marker-quota-helper.c
+++ b/xlators/features/marker/src/marker-quota-helper.c
@@ -37,23 +37,27 @@ mq_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path)
if (parent)
loc->parent = inode_ref (parent);
+ if (!uuid_is_null (inode->gfid))
+ uuid_copy (loc->gfid, inode->gfid);
+
loc->path = gf_strdup (path);
if (!loc->path) {
gf_log ("loc fill", GF_LOG_ERROR, "strdup failed");
- goto loc_wipe;
+ goto out;
}
loc->name = strrchr (loc->path, '/');
if (loc->name)
loc->name++;
else
- goto loc_wipe;
+ goto out;
ret = 0;
-loc_wipe:
+
+out:
if (ret < 0)
loc_wipe (loc);
-out:
+
return ret;
}
@@ -222,37 +226,39 @@ mq_add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx,
int32_t
-mq_dict_set_contribution (xlator_t *this, dict_t *dict,
- loc_t *loc)
+mq_dict_set_contribution (xlator_t *this, dict_t *dict, loc_t *loc,
+ uuid_t gfid, char *contri_key)
{
- int32_t ret = -1;
- char contri_key [512] = {0, };
+ int32_t ret = -1;
+ char key[CONTRI_KEY_MAX] = {0, };
GF_VALIDATE_OR_GOTO ("marker", this, out);
GF_VALIDATE_OR_GOTO ("marker", dict, out);
GF_VALIDATE_OR_GOTO ("marker", loc, out);
- if (loc->parent) {
- GET_CONTRI_KEY (contri_key, loc->parent->gfid, ret);
- if (ret < 0) {
- ret = -1;
- goto out;
- }
+ if (gfid && !uuid_is_null(gfid)) {
+ GET_CONTRI_KEY (key, gfid, ret);
+ } else if (loc->parent) {
+ GET_CONTRI_KEY (key, loc->parent->gfid, ret);
} else {
/* nameless lookup, fetch contributions to all parents */
- GET_CONTRI_KEY (contri_key, NULL, ret);
+ GET_CONTRI_KEY (key, NULL, ret);
}
- ret = dict_set_int64 (dict, contri_key, 0);
- if (ret < 0) {
- gf_log (this->name, GF_LOG_WARNING,
- "unable to set dict value on %s.",
- loc->path);
+ if (ret < 0)
goto out;
- }
- ret = 0;
+ ret = dict_set_int64 (dict, key, 0);
+ if (ret < 0)
+ goto out;
+
+ if (contri_key)
+ strncpy (contri_key, key, CONTRI_KEY_MAX);
+
out:
+ if (ret < 0)
+ gf_log_callingfn (this->name, GF_LOG_ERROR, "dict set failed");
+
return ret;
}
diff --git a/xlators/features/marker/src/marker-quota-helper.h b/xlators/features/marker/src/marker-quota-helper.h
index b200413b0ad..161413debfa 100644
--- a/xlators/features/marker/src/marker-quota-helper.h
+++ b/xlators/features/marker/src/marker-quota-helper.h
@@ -44,7 +44,7 @@ inode_contribution_t *
mq_add_new_contribution_node (xlator_t *, quota_inode_ctx_t *, loc_t *);
int32_t
-mq_dict_set_contribution (xlator_t *, dict_t *, loc_t *);
+mq_dict_set_contribution (xlator_t *, dict_t *, loc_t *, uuid_t, char *);
quota_inode_ctx_t *
mq_inode_ctx_new (inode_t *, xlator_t *);
diff --git a/xlators/features/marker/src/marker-quota.c b/xlators/features/marker/src/marker-quota.c
index b8d7a774377..835108cc403 100644
--- a/xlators/features/marker/src/marker-quota.c
+++ b/xlators/features/marker/src/marker-quota.c
@@ -20,6 +20,7 @@
#include "byte-order.h"
#include "marker-quota.h"
#include "marker-quota-helper.h"
+#include "syncop.h"
int
mq_loc_copy (loc_t *dst, loc_t *src)
@@ -478,11 +479,11 @@ mq_get_child_contribution (call_frame_t *frame,
dict_t *dict,
struct iatt *postparent)
{
- int32_t ret = -1;
- int32_t val = 0;
- char contri_key [512] = {0, };
- int64_t *contri = NULL;
- quota_local_t *local = NULL;
+ int32_t ret = -1;
+ int32_t val = 0;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ int64_t *contri = NULL;
+ quota_local_t *local = NULL;
local = frame->local;
@@ -543,16 +544,16 @@ mq_readdir_cbk (call_frame_t *frame,
int32_t op_errno,
gf_dirent_t *entries, dict_t *xdata)
{
- char contri_key [512] = {0, };
- int32_t ret = 0;
- int32_t val = 0;
- off_t offset = 0;
- int32_t count = 0;
- dict_t *dict = NULL;
- quota_local_t *local = NULL;
- gf_dirent_t *entry = NULL;
- call_frame_t *newframe = NULL;
- loc_t loc = {0, };
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ int32_t ret = 0;
+ int32_t val = 0;
+ off_t offset = 0;
+ int32_t count = 0;
+ dict_t *dict = NULL;
+ quota_local_t *local = NULL;
+ gf_dirent_t *entry = NULL;
+ call_frame_t *newframe = NULL;
+ loc_t loc = {0, };
local = mq_local_ref (frame->local);
@@ -824,7 +825,10 @@ mq_get_dirty_xattr (call_frame_t *frame, void *cookie, xlator_t *this,
if (uuid_is_null (local->loc.gfid))
uuid_copy (local->loc.gfid, local->loc.inode->gfid);
- GF_UUID_ASSERT (local->loc.gfid);
+ if (uuid_is_null (local->loc.gfid)) {
+ ret = -1;
+ goto err;
+ }
STACK_WIND (frame,
mq_check_if_still_dirty,
@@ -850,14 +854,12 @@ err:
* 0 other wise
*/
int32_t
-mq_update_dirty_inode (xlator_t *this,
- loc_t *loc,
- quota_inode_ctx_t *ctx,
+mq_update_dirty_inode (xlator_t *this, loc_t *loc, quota_inode_ctx_t *ctx,
inode_contribution_t *contribution)
{
int32_t ret = -1;
quota_local_t *local = NULL;
- gf_boolean_t status = _gf_false;
+ gf_boolean_t status = _gf_false;
struct gf_flock lock = {0, };
call_frame_t *frame = NULL;
@@ -1017,14 +1019,14 @@ err:
int32_t
mq_create_xattr (xlator_t *this, call_frame_t *frame)
{
- int32_t ret = 0;
- int64_t *value = NULL;
- int64_t *size = NULL;
- dict_t *dict = NULL;
- char key[512] = {0, };
- quota_local_t *local = NULL;
- quota_inode_ctx_t *ctx = NULL;
- inode_contribution_t *contri = NULL;
+ int32_t ret = 0;
+ int64_t *value = NULL;
+ int64_t *size = NULL;
+ dict_t *dict = NULL;
+ char key[CONTRI_KEY_MAX] = {0, };
+ quota_local_t *local = NULL;
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contri = NULL;
if (frame == NULL || this == NULL)
return 0;
@@ -1070,7 +1072,10 @@ mq_create_xattr (xlator_t *this, call_frame_t *frame)
goto free_value;
}
- GF_UUID_ASSERT (local->loc.gfid);
+ if (uuid_is_null (local->loc.gfid)) {
+ ret = -1;
+ goto out;
+ }
STACK_WIND (frame, mq_create_dirty_xattr, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->xattrop, &local->loc,
@@ -1105,11 +1110,12 @@ mq_check_n_set_inode_xattr (call_frame_t *frame, void *cookie,
inode_t *inode, struct iatt *buf, dict_t *dict,
struct iatt *postparent)
{
- quota_local_t *local = NULL;
- int64_t *size = NULL, *contri = NULL;
- int8_t dirty = 0;
- int32_t ret = 0;
- char contri_key[512] = {0, };
+ quota_local_t *local = NULL;
+ int64_t *size = NULL;
+ int64_t *contri = NULL;
+ int8_t dirty = 0;
+ int32_t ret = 0;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
if (op_ret < 0) {
goto out;
@@ -1174,7 +1180,7 @@ mq_get_xattr (call_frame_t *frame, void *cookie, xlator_t *this,
goto err;
}
- ret = mq_req_xattr (this, &local->loc, xattr_req);
+ ret = mq_req_xattr (this, &local->loc, xattr_req, NULL);
if (ret < 0) {
gf_log (this->name, GF_LOG_WARNING, "cannot request xattr");
goto err;
@@ -1183,7 +1189,10 @@ mq_get_xattr (call_frame_t *frame, void *cookie, xlator_t *this,
if (uuid_is_null (local->loc.gfid))
uuid_copy (local->loc.gfid, local->loc.inode->gfid);
- GF_UUID_ASSERT (local->loc.gfid);
+ if (uuid_is_null (local->loc.gfid)) {
+ ret = -1;
+ goto err;
+ }
STACK_WIND (frame, mq_check_n_set_inode_xattr, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->lookup, &local->loc, xattr_req);
@@ -1634,15 +1643,17 @@ mq_update_inode_contribution (call_frame_t *frame, void *cookie,
struct iatt *buf, dict_t *dict,
struct iatt *postparent)
{
- int32_t ret = -1;
- int64_t *size = NULL, size_int = 0, contri_int = 0;
- int64_t *contri = NULL;
- int64_t *delta = NULL;
- char contri_key [512] = {0, };
- dict_t *newdict = NULL;
- quota_local_t *local = NULL;
- quota_inode_ctx_t *ctx = NULL;
- inode_contribution_t *contribution = NULL;
+ int32_t ret = -1;
+ int64_t *size = NULL;
+ int64_t size_int = 0;
+ int64_t contri_int = 0;
+ int64_t *contri = NULL;
+ int64_t *delta = NULL;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ dict_t *newdict = NULL;
+ quota_local_t *local = NULL;
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contribution = NULL;
local = frame->local;
@@ -1760,11 +1771,11 @@ mq_fetch_child_size_and_contri (call_frame_t *frame, void *cookie,
xlator_t *this, int32_t op_ret,
int32_t op_errno, dict_t *xdata)
{
- int32_t ret = -1;
- char contri_key [512] = {0, };
- dict_t *newdict = NULL;
- quota_local_t *local = NULL;
- quota_inode_ctx_t *ctx = NULL;
+ int32_t ret = -1;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ dict_t *newdict = NULL;
+ quota_local_t *local = NULL;
+ quota_inode_ctx_t *ctx = NULL;
local = frame->local;
@@ -2024,19 +2035,1156 @@ err:
return -1;
}
+int32_t
+mq_dict_set_meta (dict_t *dict, char *key, const quota_meta_t *meta,
+ ia_type_t ia_type)
+{
+ int32_t ret = -1;
+ quota_meta_t *value = NULL;
+
+ QUOTA_ALLOC_OR_GOTO (value, quota_meta_t, ret, out);
+
+ value->size = hton64 (meta->size);
+ value->file_count = hton64 (meta->file_count);
+ value->dir_count = hton64 (meta->dir_count);
+
+ if (ia_type == IA_IFDIR) {
+ ret = dict_set_bin (dict, key, value, sizeof (*value));
+ } else {
+ /* For a file we don't need to store dir_count in the
+ * quota size xattr, so we set the len of the data in the dict
+ * as 128bits, so when the posix xattrop reads the dict, it only
+ * performs operations on size and file_count
+ */
+ ret = dict_set_bin (dict, key, value,
+ sizeof (*value) - sizeof (int64_t));
+ }
+
+ if (ret < 0) {
+ gf_log_callingfn ("marker", GF_LOG_ERROR, "dict set failed");
+ GF_FREE (value);
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+mq_dict_get_meta (dict_t *dict, char *key, quota_meta_t *meta)
+{
+ int32_t ret = -1;
+ data_t *data = NULL;
+ quota_meta_t *value = NULL;
+
+ if (!dict || !key || !meta)
+ goto out;
+
+ data = dict_get (dict, key);
+ if (!data || !data->data)
+ goto out;
+
+ if (data->len > sizeof (int64_t)) {
+ value = (quota_meta_t *) data->data;
+ meta->size = ntoh64 (value->size);
+ meta->file_count = ntoh64 (value->file_count);
+ if (data->len > (sizeof (int64_t)) * 2)
+ meta->dir_count = ntoh64 (value->dir_count);
+ else
+ meta->dir_count = 0;
+ } else {
+ /* This can happen during software upgrade.
+ * Older version of glusterfs will not have inode count.
+ * Return failure, this will be healed as part of lookup
+ */
+ gf_log_callingfn ("marker", GF_LOG_DEBUG, "Object quota xattrs "
+ "missing: len = %d", data->len);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+void
+mq_compute_delta (quota_meta_t *delta, const quota_meta_t *op1,
+ const quota_meta_t *op2)
+{
+ delta->size = op1->size - op2->size;
+ delta->file_count = op1->file_count - op2->file_count;
+ delta->dir_count = op1->dir_count - op2->dir_count;
+}
+
+void
+mq_add_meta (quota_meta_t *dst, const quota_meta_t *src)
+{
+ dst->size += src->size;
+ dst->file_count += src->file_count;
+ dst->dir_count += src->dir_count;
+}
+
+void
+mq_sub_meta (quota_meta_t *dst, const quota_meta_t *src)
+{
+ if (src == NULL) {
+ dst->size = -dst->size;
+ dst->file_count = -dst->file_count;
+ dst->dir_count = -dst->dir_count;
+ } else {
+ dst->size = src->size - dst->size;
+ dst->file_count = src->file_count - dst->file_count;
+ dst->dir_count = src->dir_count - dst->dir_count;
+ }
+}
+
+gf_boolean_t
+quota_meta_is_null (const quota_meta_t *meta)
+{
+ if (meta->size == 0 &&
+ meta->file_count == 0 &&
+ meta->dir_count == 0)
+ return _gf_true;
+
+ return _gf_false;
+}
+
+int32_t
+mq_are_xattrs_set (xlator_t *this, loc_t *loc, gf_boolean_t *result,
+ gf_boolean_t *objects)
+{
+ int32_t ret = -1;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ quota_meta_t meta = {0, };
+ struct iatt stbuf = {0,};
+ dict_t *dict = NULL;
+ dict_t *rsp_dict = NULL;
+
+ dict = dict_new ();
+ if (dict == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ goto out;
+ }
+
+ ret = mq_req_xattr (this, loc, dict, contri_key);
+ if (ret < 0)
+ goto out;
+
+ ret = syncop_lookup (FIRST_CHILD(this), loc, dict, &stbuf, &rsp_dict,
+ NULL);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "lookup failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ if (rsp_dict == NULL) {
+ *result = _gf_false;
+ goto out;
+ }
+
+ *result = _gf_true;
+ if (loc->inode->ia_type == IA_IFDIR) {
+ ret = mq_dict_get_meta (rsp_dict, QUOTA_SIZE_KEY, &meta);
+ if (ret < 0 || meta.dir_count == 0) {
+ ret = 0;
+ *result = _gf_false;
+ goto out;
+ }
+ *objects = _gf_true;
+ }
+
+ if (!loc_is_root(loc) && !dict_get (rsp_dict, contri_key)) {
+ *result = _gf_false;
+ goto out;
+ }
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ if (rsp_dict)
+ dict_unref (rsp_dict);
+
+ return ret;
+}
+
+int32_t
+mq_create_xattrs (xlator_t *this, loc_t *loc, gf_boolean_t objects)
+{
+ quota_meta_t size = {0, };
+ quota_meta_t contri = {0, };
+ int32_t ret = -1;
+ char key[CONTRI_KEY_MAX] = {0, };
+ dict_t *dict = NULL;
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contribution = NULL;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ ret = mq_inode_ctx_get (loc->inode, this, &ctx);
+ if (ret < 0) {
+ ctx = mq_inode_ctx_new (loc->inode, this);
+ if (ctx == NULL) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "mq_inode_ctx_new failed");
+ ret = -1;
+ goto out;
+ }
+ }
+
+ dict = dict_new ();
+ if (!dict) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ ret = -1;
+ goto out;
+ }
+
+ if (loc->inode->ia_type == IA_IFDIR) {
+ if (objects == _gf_false) {
+ /* Initial object count of a directory is 1 */
+ size.dir_count = 1;
+ }
+ ret = mq_dict_set_meta (dict, QUOTA_SIZE_KEY, &size, IA_IFDIR);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (!loc_is_root (loc)) {
+ contribution = mq_add_new_contribution_node (this, ctx, loc);
+ if (contribution == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ GET_CONTRI_KEY (key, contribution->gfid, ret);
+ ret = mq_dict_set_meta (dict, key, &contri,
+ loc->inode->ia_type);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = syncop_xattrop(FIRST_CHILD(this), loc, GF_XATTROP_ADD_ARRAY64,
+ dict, NULL);
+
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "xattrop failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ return ret;
+}
+
+int32_t
+mq_lock (xlator_t *this, loc_t *loc, short l_type)
+{
+ struct gf_flock lock = {0, };
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ gf_log (this->name, GF_LOG_DEBUG, "set lock type %d on %s",
+ l_type, loc->path);
+
+ lock.l_len = 0;
+ lock.l_start = 0;
+ lock.l_type = l_type;
+ lock.l_whence = SEEK_SET;
+
+ ret = syncop_inodelk (FIRST_CHILD(this), this->name, loc, F_SETLKW,
+ &lock, NULL, NULL);
+ if (ret < 0)
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "inodelk failed "
+ "for %s: %s", loc->path, strerror (-ret));
+
+out:
+
+ return ret;
+}
+
+int32_t
+mq_get_dirty (xlator_t *this, loc_t *loc, int32_t *dirty)
+{
+ int32_t ret = -1;
+ int8_t value = 0;
+ dict_t *dict = NULL;
+ dict_t *rsp_dict = NULL;
+ struct iatt stbuf = {0,};
+
+ dict = dict_new ();
+ if (dict == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ goto out;
+ }
+
+ ret = dict_set_int64 (dict, QUOTA_DIRTY_KEY, 0);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING, "dict set failed");
+ goto out;
+ }
+
+ ret = syncop_lookup (FIRST_CHILD(this), loc, dict, &stbuf, &rsp_dict,
+ NULL);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "lookup failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ ret = dict_get_int8 (rsp_dict, QUOTA_DIRTY_KEY, &value);
+ if (ret < 0)
+ goto out;
+
+ *dirty = value;
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ if (rsp_dict)
+ dict_unref (rsp_dict);
+
+ return ret;
+}
+
+int32_t
+mq_mark_dirty (xlator_t *this, loc_t *loc, int32_t dirty)
+{
+ int32_t ret = -1;
+ dict_t *dict = NULL;
+ quota_inode_ctx_t *ctx = NULL;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ dict = dict_new ();
+ if (!dict) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ goto out;
+ }
+
+ ret = dict_set_int8 (dict, QUOTA_DIRTY_KEY, dirty);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_set failed");
+ goto out;
+ }
+
+ ret = syncop_setxattr (FIRST_CHILD(this), loc, dict, 0);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "setxattr dirty = %d "
+ "failed for %s: %s", dirty, loc->path, strerror (-ret));
+ goto out;
+ }
+
+ ret = mq_inode_ctx_get (loc->inode, this, &ctx);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "failed to get inode ctx for "
+ "%s", loc->path);
+ goto out;
+ }
+
+ LOCK (&ctx->lock);
+ {
+ ctx->dirty = dirty;
+ }
+ UNLOCK (&ctx->lock);
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ return ret;
+}
+
+int32_t
+_mq_get_metadata (xlator_t *this, loc_t *loc, quota_meta_t *contri,
+ quota_meta_t *size, uuid_t contri_gfid)
+{
+ int32_t ret = -1;
+ quota_meta_t meta = {0, };
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ dict_t *dict = NULL;
+ dict_t *rsp_dict = NULL;
+ struct iatt stbuf = {0,};
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ if (size == NULL && contri == NULL)
+ goto out;
+
+ dict = dict_new ();
+ if (dict == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ goto out;
+ }
+
+ if (size && loc->inode->ia_type == IA_IFDIR) {
+ ret = dict_set_int64 (dict, QUOTA_SIZE_KEY, 0);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_set failed.");
+ goto out;
+ }
+ }
+
+ if (contri && !loc_is_root(loc)) {
+ ret = mq_dict_set_contribution (this, dict, loc, contri_gfid,
+ contri_key);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = syncop_lookup (FIRST_CHILD(this), loc, dict, &stbuf, &rsp_dict,
+ NULL);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "lookup failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ if (size) {
+ if (loc->inode->ia_type == IA_IFDIR) {
+ ret = mq_dict_get_meta (rsp_dict, QUOTA_SIZE_KEY,
+ &meta);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "dict_get failed.");
+ goto out;
+ }
+
+ size->size = meta.size;
+ size->file_count = meta.file_count;
+ size->dir_count = meta.dir_count;
+ } else {
+ size->size = stbuf.ia_blocks * 512;
+ size->file_count = 1;
+ size->dir_count = 0;
+ }
+ }
+
+ if (contri && !loc_is_root(loc)) {
+ ret = mq_dict_get_meta (rsp_dict, contri_key, &meta);
+ if (ret < 0) {
+ contri->size = 0;
+ contri->file_count = 0;
+ contri->dir_count = 0;
+ } else {
+ contri->size = meta.size;
+ contri->file_count = meta.file_count;
+ contri->dir_count = meta.dir_count;
+ }
+ }
+
+ ret = 0;
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ if (rsp_dict)
+ dict_unref (rsp_dict);
+
+ return ret;
+}
+
+int32_t
+mq_get_metadata (xlator_t *this, loc_t *loc, quota_meta_t *contri,
+ quota_meta_t *size, quota_inode_ctx_t *ctx,
+ inode_contribution_t *contribution)
+{
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+ GF_VALIDATE_OR_GOTO ("marker", ctx, out);
+ GF_VALIDATE_OR_GOTO ("marker", contribution, out);
+
+ if (size == NULL && contri == NULL) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = _mq_get_metadata (this, loc, contri, size, contribution->gfid);
+ if (ret < 0) {
+ gf_log_callingfn (this->name, GF_LOG_ERROR, "Failed to get "
+ "metadata for %s", loc->path);
+ goto out;
+ }
+
+ if (size) {
+ LOCK (&ctx->lock);
+ {
+ ctx->size = size->size;
+ ctx->file_count = size->file_count;
+ ctx->dir_count = size->dir_count;
+ }
+ UNLOCK (&ctx->lock);
+ }
+
+ if (contri) {
+ LOCK (&contribution->lock);
+ {
+ contribution->contribution = contri->size;
+ contribution->file_count = contri->file_count;
+ contribution->dir_count = contri->dir_count;
+ }
+ UNLOCK (&contribution->lock);
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+mq_get_size (xlator_t *this, loc_t *loc, quota_meta_t *size)
+{
+ int32_t ret = -1;
+
+ ret = _mq_get_metadata (this, loc, NULL, size, 0);
+ if (ret < 0) {
+ gf_log_callingfn (this->name, GF_LOG_ERROR, "Failed to get "
+ "metadata for %s", loc->path);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+mq_get_contri (xlator_t *this, loc_t *loc, quota_meta_t *contri,
+ uuid_t contri_gfid)
+{
+ int32_t ret = -1;
+
+ ret = _mq_get_metadata (this, loc, contri, NULL, contri_gfid);
+ if (ret < 0) {
+ gf_log_callingfn (this->name, GF_LOG_ERROR, "Failed to get "
+ "metadata for %s", loc->path);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+mq_get_delta (xlator_t *this, loc_t *loc, quota_meta_t *delta,
+ quota_inode_ctx_t *ctx, inode_contribution_t *contribution)
+{
+ int32_t ret = -1;
+ quota_meta_t size = {0, };
+ quota_meta_t contri = {0, };
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+ GF_VALIDATE_OR_GOTO ("marker", ctx, out);
+ GF_VALIDATE_OR_GOTO ("marker", contribution, out);
+
+ ret = mq_get_metadata (this, loc, &contri, &size, ctx, contribution);
+ if (ret < 0)
+ goto out;
+
+ mq_compute_delta (delta, &size, &contri);
+
+out:
+ return ret;
+}
+
+int32_t
+mq_remove_contri (xlator_t *this, loc_t *loc, inode_contribution_t *contri)
+{
+ int32_t ret = -1;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+
+ GET_CONTRI_KEY (contri_key, contri->gfid, ret);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "get contri_key "
+ "failed for %s", uuid_utoa(contri->gfid));
+ goto out;
+ }
+
+ ret = syncop_removexattr (FIRST_CHILD(this), loc, contri_key, 0);
+ if (ret < 0) {
+ if (-ret == ENOENT || -ret == ESTALE) {
+ /* Remove contri in done when unlink operation is
+ * performed, so return success on ENOENT/ESTSLE
+ */
+ ret = 0;
+ } else {
+ gf_log (this->name, GF_LOG_ERROR, "removexattr %s "
+ "failed for %s: %s", contri_key, loc->path,
+ strerror (-ret));
+ goto out;
+ }
+ }
+
+ LOCK (&contri->lock);
+ {
+ contri->contribution = 0;
+ contri->file_count = 0;
+ contri->dir_count = 0;
+ }
+ UNLOCK (&contri->lock);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+int32_t
+mq_update_contri (xlator_t *this, loc_t *loc, inode_contribution_t *contri,
+ quota_meta_t *delta)
+{
+ int32_t ret = -1;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ dict_t *dict = NULL;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+ GF_VALIDATE_OR_GOTO ("marker", delta, out);
+ GF_VALIDATE_OR_GOTO ("marker", contri, out);
+
+ if (quota_meta_is_null (delta)) {
+ ret = 0;
+ goto out;
+ }
+
+ dict = dict_new ();
+ if (!dict) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ ret = -1;
+ goto out;
+ }
+
+ GET_CONTRI_KEY (contri_key, contri->gfid, ret);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "get contri_key "
+ "failed for %s", uuid_utoa(contri->gfid));
+ goto out;
+ }
+
+ ret = mq_dict_set_meta (dict, contri_key, delta, loc->inode->ia_type);
+ if (ret < 0)
+ goto out;
+
+ ret = syncop_xattrop(FIRST_CHILD(this), loc, GF_XATTROP_ADD_ARRAY64,
+ dict, NULL);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "xattrop failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ LOCK (&contri->lock);
+ {
+ contri->contribution += delta->size;
+ contri->file_count += delta->file_count;
+ contri->dir_count += delta->dir_count;
+ }
+ UNLOCK (&contri->lock);
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ return ret;
+}
+
+int32_t
+mq_update_size (xlator_t *this, loc_t *loc, quota_meta_t *delta)
+{
+ int32_t ret = -1;
+ quota_inode_ctx_t *ctx = NULL;
+ dict_t *dict = NULL;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+ GF_VALIDATE_OR_GOTO ("marker", delta, out);
+
+ if (quota_meta_is_null (delta)) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = mq_inode_ctx_get (loc->inode, this, &ctx);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "failed to get inode ctx for "
+ "%s", loc->path);
+ goto out;
+ }
+
+ dict = dict_new ();
+ if (!dict) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
+ ret = -1;
+ goto out;
+ }
+
+ ret = mq_dict_set_meta (dict, QUOTA_SIZE_KEY, delta,
+ loc->inode->ia_type);
+ if (ret < 0)
+ goto out;
+
+ ret = syncop_xattrop(FIRST_CHILD(this), loc, GF_XATTROP_ADD_ARRAY64,
+ dict, NULL);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "xattrop failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ LOCK (&ctx->lock);
+ {
+ ctx->size += delta->size;
+ ctx->file_count += delta->file_count;
+ ctx->dir_count += delta->dir_count;
+ }
+ UNLOCK (&ctx->lock);
+
+out:
+ if (dict)
+ dict_unref (dict);
+
+ return ret;
+}
int
-mq_initiate_quota_txn (xlator_t *this, loc_t *loc)
+mq_synctask_cleanup (int ret, call_frame_t *frame, void *opaque)
{
- int32_t ret = -1;
- gf_boolean_t status = _gf_false;
- quota_inode_ctx_t *ctx = NULL;
- inode_contribution_t *contribution = NULL;
+ quota_synctask_t *args = NULL;
+
+ GF_ASSERT (opaque);
+
+ args = (quota_synctask_t *) opaque;
+ loc_wipe (&args->loc);
+ if (args->dict)
+ dict_unref (args->dict);
+
+ if (!args->is_static)
+ GF_FREE (args);
+
+ return 0;
+}
+
+int
+mq_synctask (xlator_t *this, synctask_fn_t task, gf_boolean_t spawn, loc_t *loc,
+ dict_t *dict, struct iatt *buf, int64_t contri)
+{
+ int32_t ret = -1;
+ quota_synctask_t *args = NULL;
+ quota_synctask_t static_args = {0, };
+
+ if (spawn) {
+ QUOTA_ALLOC_OR_GOTO (args, quota_synctask_t, ret, out);
+ args->is_static = _gf_false;
+ } else {
+ args = &static_args;
+ args->is_static = _gf_true;
+ }
+
+ args->this = this;
+ loc_copy (&args->loc, loc);
+ args->contri = contri;
+ if (dict)
+ args->dict = dict_ref (dict);
+ if (buf)
+ args->buf = *buf;
+
+
+ if (spawn) {
+ ret = synctask_new (this->ctx->env, task, mq_synctask_cleanup,
+ NULL, args);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to spawn "
+ "new synctask");
+ mq_synctask_cleanup (ret, NULL, args);
+ }
+ } else {
+ ret = task (args);
+ mq_synctask_cleanup (ret, NULL, args);
+ }
+
+out:
+ return ret;
+}
+
+int
+mq_start_quota_txn_v2 (xlator_t *this, loc_t *loc, quota_inode_ctx_t *ctx,
+ inode_contribution_t *contri)
+{
+ int32_t ret = -1;
+ loc_t child_loc = {0,};
+ loc_t parent_loc = {0,};
+ gf_boolean_t locked = _gf_false;
+ gf_boolean_t dirty = _gf_false;
+ gf_boolean_t status = _gf_true;
+ quota_meta_t delta = {0, };
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+ GF_VALIDATE_OR_GOTO ("marker", ctx, out);
+ GF_VALIDATE_OR_GOTO ("marker", contri, out);
+
+ ret = mq_loc_copy (&child_loc, loc);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "loc copy failed");
+ goto out;
+ }
+
+ if (uuid_is_null (child_loc.gfid))
+ uuid_copy (child_loc.gfid, child_loc.inode->gfid);
+
+ if (uuid_is_null (child_loc.gfid)) {
+ ret = -1;
+ gf_log (this->name, GF_LOG_DEBUG, "UUID is null for %s",
+ child_loc.path);
+ goto out;
+ }
+
+ while (!__is_root_gfid (child_loc.gfid)) {
+ /* To improve performance, abort current transaction
+ * if one is already in progress for same inode
+ */
+ ret = mq_test_and_set_ctx_updation_status (ctx, &status);
+ if (ret < 0 || status == _gf_true)
+ goto out;
+
+ ret = mq_inode_loc_fill (NULL, child_loc.parent, &parent_loc);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "loc fill failed");
+ goto out;
+ }
+
+ ret = mq_lock (this, &parent_loc, F_WRLCK);
+ if (ret < 0)
+ goto out;
+ locked = _gf_true;
+
+ mq_set_ctx_updation_status (ctx, _gf_false);
+ status = _gf_true;
+
+ ret = mq_get_delta (this, &child_loc, &delta, ctx, contri);
+ if (ret < 0)
+ goto out;
+
+ if (quota_meta_is_null (&delta))
+ goto out;
+
+ ret = mq_mark_dirty (this, &parent_loc, 1);
+ if (ret < 0)
+ goto out;
+ dirty = _gf_true;
+
+ ret = mq_update_contri (this, &child_loc, contri, &delta);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "contri "
+ "update failed for %s", child_loc.path);
+ goto out;
+ }
+
+ ret = mq_update_size (this, &parent_loc, &delta);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING, "rollback "
+ "contri updation");
+ mq_sub_meta (&delta, NULL);
+ mq_update_contri (this, &child_loc, contri, &delta);
+ goto out;
+ }
+
+ ret = mq_mark_dirty (this, &parent_loc, 0);
+ dirty = _gf_false;
+
+ ret = mq_lock (this, &parent_loc, F_UNLCK);
+ locked = _gf_false;
+
+ if (__is_root_gfid (parent_loc.gfid))
+ break;
+
+ /* Repeate above steps upwards till the root */
+ loc_wipe (&child_loc);
+ ret = mq_loc_copy (&child_loc, &parent_loc);
+ if (ret < 0)
+ goto out;
+ loc_wipe (&parent_loc);
+
+ ret = mq_inode_ctx_get (child_loc.inode, this, &ctx);
+ if (ret < 0)
+ goto out;
+
+ if (list_empty (&ctx->contribution_head)) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "contribution node list is empty (%s)",
+ uuid_utoa(child_loc.inode->gfid));
+ ret = -1;
+ goto out;
+ }
+ contri = mq_get_contribution_node (child_loc.parent, ctx);
+ GF_ASSERT (contri != NULL);
+ }
+
+out:
+ if (ret >= 0 && dirty)
+ ret = mq_mark_dirty (this, &parent_loc, 0);
+
+ if (locked)
+ ret = mq_lock (this, &parent_loc, F_UNLCK);
+
+ if (status == _gf_false)
+ mq_set_ctx_updation_status (ctx, _gf_false);
+
+ loc_wipe (&child_loc);
+ loc_wipe (&parent_loc);
+
+ return ret;
+}
+
+int
+mq_create_xattrs_task (void *opaque)
+{
+ int32_t ret = -1;
+ gf_boolean_t locked = _gf_false;
+ gf_boolean_t xattrs_set = _gf_false;
+ gf_boolean_t objects = _gf_false;
+ gf_boolean_t need_txn = _gf_false;
+ quota_synctask_t *args = NULL;
+ xlator_t *this = NULL;
+ loc_t *loc = NULL;
+
+ GF_ASSERT (opaque);
+
+ args = (quota_synctask_t *) opaque;
+ loc = &args->loc;
+ this = args->this;
+ THIS = this;
+
+ if (uuid_is_null (loc->gfid))
+ uuid_copy (loc->gfid, loc->inode->gfid);
+
+ if (uuid_is_null (loc->gfid)) {
+ ret = -1;
+ gf_log (this->name, GF_LOG_DEBUG, "UUID is null for %s",
+ loc->path);
+ goto out;
+ }
+
+ ret = mq_lock (this, loc, F_WRLCK);
+ if (ret < 0)
+ goto out;
+ locked = _gf_true;
+
+ ret = mq_are_xattrs_set (this, loc, &xattrs_set, &objects);
+ if (ret < 0 || xattrs_set)
+ goto out;
+
+ ret = mq_create_xattrs (this, loc, objects);
+ if (ret < 0)
+ goto out;
+
+ need_txn = _gf_true;
+out:
+ if (locked)
+ ret = mq_lock (this, loc, F_UNLCK);
+
+ if (need_txn)
+ ret = mq_initiate_quota_blocking_txn (this, loc);
+
+ return ret;
+}
+
+int
+mq_create_xattrs_txn (xlator_t *this, loc_t *loc)
+{
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ ret = mq_synctask (this, mq_create_xattrs_task, _gf_true, loc, NULL,
+ NULL, 0);
+out:
+ return ret;
+}
+
+int
+mq_create_xattrs_blocking_txn (xlator_t *this, loc_t *loc)
+{
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ ret = mq_synctask (this, mq_create_xattrs_task, _gf_false, loc, NULL,
+ NULL, 0);
+out:
+ return ret;
+}
+
+int32_t
+mq_reduce_parent_size_task (void *opaque)
+{
+ int32_t ret = -1;
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contribution = NULL;
+ quota_meta_t delta = {0, };
+ loc_t parent_loc = {0,};
+ gf_boolean_t locked = _gf_false;
+ gf_boolean_t dirty = _gf_false;
+ quota_synctask_t *args = NULL;
+ xlator_t *this = NULL;
+ loc_t *loc = NULL;
+ int64_t contri = 0;
+
+ GF_ASSERT (opaque);
+
+ args = (quota_synctask_t *) opaque;
+ loc = &args->loc;
+ contri = args->contri;
+ this = args->this;
+ THIS = this;
+
+ ret = mq_inode_ctx_get (loc->inode, this, &ctx);
+ if (ret < 0) {
+ gf_log_callingfn (this->name, GF_LOG_WARNING, "ctx for"
+ " the node %s is NULL", loc->path);
+ goto out;
+ }
+
+ contribution = mq_get_contribution_node (loc->parent, ctx);
+ if (contribution == NULL) {
+ ret = -1;
+ gf_log_callingfn (this->name, GF_LOG_WARNING,
+ "contribution for the node %s is NULL",
+ loc->path);
+ goto out;
+ }
+
+ if (contri >= 0) {
+ /* contri paramater is supplied only for rename operation */
+ delta.size = contri;
+ delta.file_count = 1;
+ delta.dir_count = 0;
+ }
+
+ ret = mq_inode_loc_fill (NULL, loc->parent, &parent_loc);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "loc fill failed");
+ goto out;
+ }
+
+ ret = mq_lock (this, &parent_loc, F_WRLCK);
+ if (ret < 0)
+ goto out;
+ locked = _gf_true;
+
+ if (contri < 0) {
+ LOCK (&contribution->lock);
+ {
+ delta.size = contribution->contribution;
+ delta.file_count = contribution->file_count;
+ delta.dir_count = contribution->dir_count;
+ }
+ UNLOCK (&contribution->lock);
+ }
+
+ /* TODO: Handle handlinks with better approach
+ Iterating dentry_list without a lock is not a good idea
+ if (loc->inode->ia_type != IA_IFDIR) {
+ list_for_each_entry (dentry, &inode->dentry_list, inode_list) {
+ if (loc->parent == dentry->parent) {
+ * If the file has another link within the same
+ * directory, we should not be reducing the size
+ * of parent
+ *
+ delta = 0;
+ idelta = 0;
+ break;
+ }
+ }
+ }
+ */
+
+ if (quota_meta_is_null (&delta))
+ goto out;
+
+ ret = mq_mark_dirty (this, &parent_loc, 1);
+ if (ret < 0)
+ goto out;
+ dirty = _gf_true;
+
+ ret = mq_remove_contri (this, loc, contribution);
+ if (ret < 0)
+ goto out;
+
+ mq_sub_meta (&delta, NULL);
+ ret = mq_update_size (this, &parent_loc, &delta);
+ if (ret < 0)
+ goto out;
+
+out:
+ if (dirty && ret >= 0)
+ ret = mq_mark_dirty (this, &parent_loc, 0);
+
+ if (locked)
+ ret = mq_lock (this, &parent_loc, F_UNLCK);
+
+ if (ret >= 0)
+ ret = mq_initiate_quota_blocking_txn (this, &parent_loc);
+
+ loc_wipe (&parent_loc);
+
+ return ret;
+}
+
+int32_t
+mq_reduce_parent_size_txn (xlator_t *this, loc_t *loc, int64_t contri)
+{
+ int32_t ret = -1;
GF_VALIDATE_OR_GOTO ("marker", this, out);
GF_VALIDATE_OR_GOTO ("marker", loc, out);
GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+ ret = mq_synctask (this, mq_reduce_parent_size_task, _gf_true, loc,
+ NULL, NULL, contri);
+out:
+ return ret;
+}
+
+int
+mq_initiate_quota_task (void *opaque)
+{
+ int32_t ret = -1;
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contribution = NULL;
+ quota_synctask_t *args = NULL;
+ xlator_t *this = NULL;
+ loc_t *loc = NULL;
+
+ GF_ASSERT (opaque);
+
+ args = (quota_synctask_t *) opaque;
+ loc = &args->loc;
+ this = args->this;
+ THIS = this;
+
ret = mq_inode_ctx_get (loc->inode, this, &ctx);
if (ret == -1) {
gf_log (this->name, GF_LOG_WARNING,
@@ -2057,69 +3205,259 @@ mq_initiate_quota_txn (xlator_t *this, loc_t *loc)
*/
contribution = mq_get_contribution_node (loc->parent, ctx);
if (!contribution) {
- if ((loc->path && strcmp (loc->path, "/"))
- || (!uuid_is_null (loc->gfid)
- && !__is_root_gfid (loc->gfid))
- || (loc->inode && !uuid_is_null (loc->inode->gfid)
- && !__is_root_gfid (loc->inode->gfid)))
+ if (!loc_is_root(loc))
gf_log_callingfn (this->name, GF_LOG_TRACE,
"contribution node for the "
"path (%s) with parent (%s) "
"not found", loc->path,
- loc->parent?
- uuid_utoa (loc->parent->gfid):
+ loc->parent ?
+ uuid_utoa (loc->parent->gfid) :
NULL);
contribution = mq_add_new_contribution_node (this, ctx, loc);
if (!contribution) {
- if(loc->path && strcmp (loc->path, "/"))
+ if (!loc_is_root(loc))
gf_log_callingfn (this->name, GF_LOG_WARNING,
"could not allocate "
" contribution node for (%s) "
"parent: (%s)", loc->path,
- loc->parent?
- uuid_utoa (loc->parent->gfid):
+ loc->parent ?
+ uuid_utoa (loc->parent->gfid) :
NULL);
goto out;
}
}
- /* To improve performance, do not start another transaction
- * if one is already in progress for same inode
- */
- status = _gf_true;
+ mq_start_quota_txn_v2 (this, loc, ctx, contribution);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int
+mq_initiate_quota_txn (xlator_t *this, loc_t *loc)
+{
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("marker", this, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ ret = mq_synctask (this, mq_initiate_quota_task, _gf_true, loc, NULL,
+ NULL, 0);
+out:
+ return ret;
+}
+
+int
+mq_initiate_quota_blocking_txn (xlator_t *this, loc_t *loc)
+{
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("marker", this, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ ret = mq_synctask (this, mq_initiate_quota_task, _gf_false, loc, NULL,
+ NULL, 0);
+out:
+ return ret;
+}
+
+/* return 1 when dirty updation is performed
+ * return 0 other wise
+ */
+int32_t
+mq_update_dirty_inode_v2 (xlator_t *this, loc_t *loc, quota_inode_ctx_t *ctx,
+ inode_contribution_t *contribution)
+{
+ int32_t ret = -1;
+ fd_t *fd = NULL;
+ off_t offset = 0;
+ loc_t child_loc = {0, };
+ gf_dirent_t entries;
+ gf_dirent_t *entry = NULL;
+ gf_boolean_t status = _gf_true;
+ gf_boolean_t locked = _gf_false;
+ gf_boolean_t free_entries = _gf_false;
+ gf_boolean_t updated = _gf_false;
+ int32_t dirty = 0;
+ quota_meta_t contri = {0, };
+ quota_meta_t size = {0, };
+ quota_meta_t contri_sum = {0, };
+ quota_meta_t delta = {0, };
+
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc->inode, out);
+
+ ret = mq_get_ctx_updation_status (ctx, &status);
+ if (ret == -1 || status == _gf_true) {
+ ret = 0;
+ goto out;
+ }
+
+ if (uuid_is_null (loc->gfid))
+ uuid_copy (loc->gfid, loc->inode->gfid);
- ret = mq_test_and_set_ctx_updation_status (ctx, &status);
+ if (uuid_is_null (loc->gfid)) {
+ ret = -1;
+ gf_log (this->name, GF_LOG_DEBUG, "UUID is null for %s",
+ loc->path);
+ goto out;
+ }
+
+ ret = mq_lock (this, loc, F_WRLCK);
if (ret < 0)
goto out;
+ locked = _gf_true;
- if (status == _gf_false) {
- mq_start_quota_txn (this, loc, ctx, contribution);
+ ret = mq_get_dirty (this, loc, &dirty);
+ if (ret < 0 || dirty == 0) {
+ ret = 0;
+ goto out;
}
- ret = 0;
+ fd = fd_create (loc->inode, 0);
+ if (!fd) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to create fd");
+ ret = -1;
+ goto out;
+ }
+
+ ret = syncop_opendir (this, loc, fd);
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "opendir failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ INIT_LIST_HEAD (&entries.list);
+ while ((ret = syncop_readdirp (this, fd, 131072, offset, NULL,
+ &entries)) != 0) {
+ if (ret < 0) {
+ gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
+ ? GF_LOG_DEBUG:GF_LOG_ERROR, "readdirp failed "
+ "for %s: %s", loc->path, strerror (-ret));
+ goto out;
+ }
+
+ if (list_empty (&entries.list))
+ break;
+
+ free_entries = _gf_true;
+ list_for_each_entry (entry, &entries.list, list) {
+ offset = entry->d_off;
+
+ if (!strcmp (entry->d_name, ".") ||
+ !strcmp (entry->d_name, ".."))
+ continue;
+
+ ret = loc_build_child (&child_loc, loc, entry->d_name);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "Couldn't build loc for %s/%s "
+ "returning from updation of dirty "
+ "inode", loc->path, entry->d_name);
+ goto out;
+ }
+
+ ret = mq_get_contri (this, &child_loc, &contri,
+ loc->gfid);
+ if (ret < 0)
+ goto out;
+
+ mq_add_meta (&contri_sum, &contri);
+ loc_wipe (&child_loc);
+ }
+
+ gf_dirent_free (&entries);
+ free_entries = _gf_false;
+ }
+ /* Inculde for self */
+ contri_sum.dir_count++;
+
+ ret = mq_get_size (this, loc, &size);
+ if (ret < 0)
+ goto out;
+
+ mq_compute_delta (&delta, &contri_sum, &size);
+
+ if (quota_meta_is_null (&delta))
+ goto out;
+
+ gf_log (this->name, GF_LOG_INFO, "calculated size = %"PRId64
+ ", original size = %"PRIu64 ", diff = %"PRIu64
+ ", path = %s ", contri_sum.size, size.size, delta.size,
+ loc->path);
+
+ gf_log (this->name, GF_LOG_INFO, "calculated f_count = %"PRId64
+ ", original f_count = %"PRIu64 ", diff = %"PRIu64
+ ", path = %s ", contri_sum.file_count, size.file_count,
+ delta.file_count, loc->path);
+
+ gf_log (this->name, GF_LOG_INFO, "calculated d_count = %"PRId64
+ ", original d_count = %"PRIu64 ", diff = %"PRIu64
+ ", path = %s ", contri_sum.dir_count, size.dir_count,
+ delta.dir_count, loc->path);
+
+
+ ret = mq_update_size (this, loc, &delta);
+ if (ret < 0)
+ goto out;
+
+ updated = _gf_true;
+
out:
- return ret;
-}
+ if (free_entries)
+ gf_dirent_free (&entries);
+ if (fd)
+ fd_unref (fd);
+
+ if (ret >= 0 && dirty)
+ mq_mark_dirty (this, loc, 0);
+
+ if (locked)
+ mq_lock (this, loc, F_UNLCK);
+ if (status == _gf_false)
+ mq_set_ctx_updation_status (ctx, _gf_false);
+ loc_wipe(&child_loc);
+ if (updated)
+ return 1;
+ else
+ return 0;
+}
int32_t
-mq_inspect_directory_xattr (xlator_t *this,
- loc_t *loc,
- dict_t *dict,
- struct iatt buf)
+mq_inspect_directory_xattr_task (void *opaque)
{
- int32_t ret = 0;
- int8_t dirty = -1;
- int64_t *size = NULL, size_int = 0;
- int64_t *contri = NULL, contri_int = 0;
- char contri_key [512] = {0, };
- gf_boolean_t not_root = _gf_false;
- quota_inode_ctx_t *ctx = NULL;
- inode_contribution_t *contribution = NULL;
+ int32_t ret = 0;
+ int8_t dirty = -1;
+ quota_meta_t size = {0, };
+ quota_meta_t contri = {0, };
+ quota_meta_t delta = {0, };
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contribution = NULL;
+ quota_synctask_t *args = NULL;
+ xlator_t *this = NULL;
+ loc_t *loc = NULL;
+ dict_t *dict = NULL;
+ struct iatt buf = {0,};
+
+ GF_ASSERT (opaque);
+
+ args = (quota_synctask_t *) opaque;
+ loc = &args->loc;
+ dict = args->dict;
+ buf = args->buf;
+ this = args->this;
+ THIS = this;
ret = mq_inode_ctx_get (loc->inode, this, &ctx);
if (ret < 0) {
@@ -2132,7 +3470,7 @@ mq_inspect_directory_xattr (xlator_t *this,
}
}
- if (!loc->path || (loc->path && strcmp (loc->path, "/") != 0)) {
+ if (!loc_is_root(loc)) {
contribution = mq_add_new_contribution_node (this, ctx, loc);
if (contribution == NULL) {
if (!uuid_is_null (loc->inode->gfid))
@@ -2144,76 +3482,96 @@ mq_inspect_directory_xattr (xlator_t *this,
}
}
- ret = dict_get_bin (dict, QUOTA_SIZE_KEY, (void **) &size);
+ ret = dict_get_int8 (dict, QUOTA_DIRTY_KEY, &dirty);
if (ret < 0)
goto out;
- ret = dict_get_int8 (dict, QUOTA_DIRTY_KEY, &dirty);
+ ret = mq_dict_get_meta (dict, QUOTA_SIZE_KEY, &size);
if (ret < 0)
goto out;
- if ((loc->path && strcmp (loc->path, "/") != 0)
- || (!uuid_is_null (loc->gfid) && !__is_root_gfid (loc->gfid))
- || (loc->inode && !uuid_is_null (loc->inode->gfid) &&
- !__is_root_gfid (loc->inode->gfid))) {
- not_root = _gf_true;
-
+ if (!loc_is_root(loc)) {
GET_CONTRI_KEY (contri_key, contribution->gfid, ret);
if (ret < 0)
- goto out;
+ goto err;
- ret = dict_get_bin (dict, contri_key, (void **) &contri);
+ ret = mq_dict_get_meta (dict, contri_key, &contri);
if (ret < 0)
goto out;
LOCK (&contribution->lock);
{
- contribution->contribution = ntoh64 (*contri);
- contri_int = contribution->contribution;
+ contribution->contribution = contri.size;
+ contribution->file_count = contri.file_count;
+ contribution->dir_count = contri.dir_count;
}
UNLOCK (&contribution->lock);
}
LOCK (&ctx->lock);
{
- ctx->size = ntoh64 (*size);
+ ctx->size = size.size;
+ ctx->file_count = size.file_count;
+ ctx->dir_count = size.dir_count;
ctx->dirty = dirty;
- size_int = ctx->size;
}
UNLOCK (&ctx->lock);
- gf_log (this->name, GF_LOG_DEBUG, "size=%"PRId64
- " contri=%"PRId64, size_int, contri_int);
+ mq_compute_delta (&delta, &size, &contri);
- if (dirty) {
- ret = mq_update_dirty_inode (this, loc, ctx, contribution);
- }
+ if (dirty)
+ ret = mq_update_dirty_inode_v2 (this, loc, ctx, contribution);
- if ((!dirty || ret == 0) && (not_root == _gf_true) &&
- (size_int != contri_int)) {
- mq_initiate_quota_txn (this, loc);
- }
+ if ((!dirty || ret == 1) &&
+ !loc_is_root(loc) &&
+ !quota_meta_is_null (&delta))
+ mq_initiate_quota_blocking_txn (this, loc);
ret = 0;
out:
- if (ret)
- mq_set_inode_xattr (this, loc);
+ if (ret < 0)
+ ret = mq_create_xattrs_blocking_txn (this, loc);
+
err:
return ret;
}
int32_t
-mq_inspect_file_xattr (xlator_t *this,
- loc_t *loc,
- dict_t *dict,
- struct iatt buf)
+mq_inspect_directory_xattr_txn (xlator_t *this, loc_t *loc, dict_t *dict,
+ struct iatt buf)
{
- int32_t ret = -1;
- uint64_t contri_int = 0, size = 0;
- int64_t *contri_ptr = NULL;
- char contri_key [512] = {0, };
- quota_inode_ctx_t *ctx = NULL;
- inode_contribution_t *contribution = NULL;
+ int32_t ret = -1;
+
+ ret = mq_synctask (this, mq_inspect_directory_xattr_task, _gf_true,
+ loc, dict, &buf, 0);
+
+ return ret;
+}
+
+int32_t
+mq_inspect_file_xattr_task (void *opaque)
+{
+ int32_t ret = -1;
+ quota_meta_t size = {0, };
+ quota_meta_t contri = {0, };
+ quota_meta_t delta = {0, };
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ quota_inode_ctx_t *ctx = NULL;
+ inode_contribution_t *contribution = NULL;
+ quota_synctask_t *args = NULL;
+ xlator_t *this = NULL;
+ loc_t *loc = NULL;
+ dict_t *dict = NULL;
+ struct iatt buf = {0,};
+
+ GF_ASSERT (opaque);
+
+ args = (quota_synctask_t *) opaque;
+ loc = &args->loc;
+ dict = args->dict;
+ buf = args->buf;
+ this = args->this;
+ THIS = this;
ret = mq_inode_ctx_get (loc->inode, this, &ctx);
if (ret < 0) {
@@ -2230,103 +3588,111 @@ mq_inspect_file_xattr (xlator_t *this,
if (contribution == NULL) {
gf_log_callingfn (this->name, GF_LOG_DEBUG, "cannot allocate "
"contribution node (path:%s)", loc->path);
+ ret = -1;
goto out;
}
LOCK (&ctx->lock);
{
ctx->size = 512 * buf.ia_blocks;
- size = ctx->size;
+ ctx->file_count = 1;
+ ctx->dir_count = 0;
+
+ size.size = ctx->size;
+ size.file_count = ctx->file_count;
+ size.dir_count = ctx->dir_count;
}
UNLOCK (&ctx->lock);
list_for_each_entry (contribution, &ctx->contribution_head,
contri_list) {
+
GET_CONTRI_KEY (contri_key, contribution->gfid, ret);
if (ret < 0)
continue;
- ret = dict_get_bin (dict, contri_key, (void **) &contri_int);
- if (ret == 0) {
- contri_ptr = (int64_t *)(unsigned long)contri_int;
-
+ ret = mq_dict_get_meta (dict, contri_key, &contri);
+ if (ret < 0) {
+ ret = mq_create_xattrs_blocking_txn (this, loc);
+ } else {
LOCK (&contribution->lock);
{
- contribution->contribution = ntoh64 (*contri_ptr);
- contri_int = contribution->contribution;
+ contribution->contribution = contri.size;
+ contribution->file_count = contri.file_count;
+ contribution->dir_count = contri.dir_count;
}
UNLOCK (&contribution->lock);
- gf_log (this->name, GF_LOG_DEBUG,
- "size=%"PRId64 " contri=%"PRId64, size, contri_int);
-
- if (size != contri_int) {
- mq_initiate_quota_txn (this, loc);
+ mq_compute_delta (&delta, &size, &contri);
+ if (!quota_meta_is_null (&delta)) {
+ mq_initiate_quota_blocking_txn (this, loc);
+ /* TODO: revist this code when fixing hardlinks
+ */
+ break;
}
- } else {
- if (size)
- mq_initiate_quota_txn (this, loc);
- else
- mq_set_inode_xattr (this, loc);
}
+
+ /* TODO: loc->parent might need to be assigned to corresponding
+ * contribution inode. We need to handle hard links here
+ */
}
out:
+
return ret;
}
int32_t
-mq_xattr_state (xlator_t *this,
- loc_t *loc,
- dict_t *dict,
- struct iatt buf)
+mq_inspect_file_xattr_txn (xlator_t *this, loc_t *loc, dict_t *dict,
+ struct iatt buf)
+{
+ int32_t ret = -1;
+
+ ret = mq_synctask (this, mq_inspect_file_xattr_task, _gf_true,
+ loc, dict, &buf, 0);
+
+ return ret;
+}
+
+int32_t
+mq_xattr_state (xlator_t *this, loc_t *loc, dict_t *dict, struct iatt buf)
{
if (((buf.ia_type == IA_IFREG) && !dht_is_linkfile (&buf, dict))
|| (buf.ia_type == IA_IFLNK)) {
- mq_inspect_file_xattr (this, loc, dict, buf);
+ mq_inspect_file_xattr_txn (this, loc, dict, buf);
} else if (buf.ia_type == IA_IFDIR)
- mq_inspect_directory_xattr (this, loc, dict, buf);
+ mq_inspect_directory_xattr_txn (this, loc, dict, buf);
return 0;
}
int32_t
-mq_req_xattr (xlator_t *this,
- loc_t *loc,
- dict_t *dict)
+mq_req_xattr (xlator_t *this, loc_t *loc, dict_t *dict,
+ char *contri_key)
{
int32_t ret = -1;
GF_VALIDATE_OR_GOTO ("marker", this, out);
+ GF_VALIDATE_OR_GOTO ("marker", loc, out);
GF_VALIDATE_OR_GOTO ("marker", dict, out);
- if (!loc)
- goto set_size;
-
- //if not "/" then request contribution
- if (loc->path && strcmp (loc->path, "/") == 0)
- goto set_size;
-
- ret = mq_dict_set_contribution (this, dict, loc);
- if (ret == -1)
- goto out;
+ if (!loc_is_root(loc)) {
+ ret = mq_dict_set_contribution (this, dict, loc, NULL,
+ contri_key);
+ if (ret < 0)
+ goto out;
+ }
-set_size:
ret = dict_set_uint64 (dict, QUOTA_SIZE_KEY, 0);
- if (ret < 0) {
- ret = -1;
+ if (ret < 0)
goto out;
- }
ret = dict_set_int8 (dict, QUOTA_DIRTY_KEY, 0);
- if (ret < 0) {
- ret = -1;
- goto out;
- }
-
- ret = 0;
out:
+ if (ret < 0)
+ gf_log_callingfn (this->name, GF_LOG_ERROR, "dict set failed");
+
return ret;
}
@@ -2344,15 +3710,15 @@ int32_t
_mq_inode_remove_done (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, dict_t *xdata)
{
- int32_t ret = 0;
- char contri_key [512] = {0, };
- quota_local_t *local = NULL;
- inode_t *inode = NULL;
- dentry_t *tmp = NULL;
- gf_boolean_t last_dentry = _gf_true;
- loc_t loc = {0, };
- dentry_t *other_dentry = NULL;
- gf_boolean_t remove = _gf_false;
+ int32_t ret = 0;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ quota_local_t *local = NULL;
+ inode_t *inode = NULL;
+ dentry_t *tmp = NULL;
+ gf_boolean_t last_dentry = _gf_true;
+ loc_t loc = {0, };
+ dentry_t *other_dentry = NULL;
+ gf_boolean_t remove = _gf_false;
local = (quota_local_t *) frame->local;
@@ -2531,6 +3897,7 @@ mq_reduce_parent_size_xattr (call_frame_t *frame, void *cookie, xlator_t *this,
dict = dict_new ();
if (dict == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
ret = -1;
goto err;
}
diff --git a/xlators/features/marker/src/marker-quota.h b/xlators/features/marker/src/marker-quota.h
index 42def9d22dc..fa132a815b7 100644
--- a/xlators/features/marker/src/marker-quota.h
+++ b/xlators/features/marker/src/marker-quota.h
@@ -21,7 +21,7 @@
#define QUOTA_XATTR_PREFIX "trusted.glusterfs"
#define QUOTA_DIRTY_KEY "trusted.glusterfs.quota.dirty"
-#define CONTRIBUTION "contri"
+#define CONTRIBUTION "contri"
#define CONTRI_KEY_MAX 512
#define READDIR_BUF 4096
@@ -59,21 +59,21 @@
ret = 0; \
} while (0);
-#define GET_CONTRI_KEY(var, _gfid, _ret) \
- do { \
- if (_gfid != NULL) { \
- char _gfid_unparsed[40]; \
- uuid_unparse (_gfid, _gfid_unparsed); \
- _ret = snprintf (var, CONTRI_KEY_MAX, \
- QUOTA_XATTR_PREFIX \
+#define GET_CONTRI_KEY(var, _gfid, _ret) \
+ do { \
+ if (_gfid != NULL) { \
+ char _gfid_unparsed[40]; \
+ uuid_unparse (_gfid, _gfid_unparsed); \
+ _ret = snprintf (var, CONTRI_KEY_MAX, \
+ QUOTA_XATTR_PREFIX \
".%s.%s." CONTRIBUTION, "quota", \
- _gfid_unparsed); \
- } else { \
- _ret = snprintf (var, CONTRI_KEY_MAX, \
- QUOTA_XATTR_PREFIX \
- ".%s.." CONTRIBUTION, "quota"); \
- } \
- } while (0);
+ _gfid_unparsed); \
+ } else { \
+ _ret = snprintf (var, CONTRI_KEY_MAX, \
+ QUOTA_XATTR_PREFIX \
+ ".%s.." CONTRIBUTION, "quota"); \
+ } \
+ } while (0)
#define QUOTA_SAFE_INCREMENT(lock, var) \
do { \
@@ -84,6 +84,8 @@
struct quota_inode_ctx {
int64_t size;
+ int64_t file_count;
+ int64_t dir_count;
int8_t dirty;
gf_boolean_t updation_status;
gf_lock_t lock;
@@ -91,9 +93,28 @@ struct quota_inode_ctx {
};
typedef struct quota_inode_ctx quota_inode_ctx_t;
+struct quota_meta {
+ int64_t size;
+ int64_t file_count;
+ int64_t dir_count;
+};
+typedef struct quota_meta quota_meta_t;
+
+struct quota_synctask {
+ xlator_t *this;
+ loc_t loc;
+ dict_t *dict;
+ struct iatt buf;
+ int64_t contri;
+ gf_boolean_t is_static;
+};
+typedef struct quota_synctask quota_synctask_t;
+
struct inode_contribution {
struct list_head contri_list;
int64_t contribution;
+ int64_t file_count;
+ int64_t dir_count;
uuid_t gfid;
gf_lock_t lock;
};
@@ -103,7 +124,7 @@ int32_t
mq_get_lock_on_parent (call_frame_t *, xlator_t *);
int32_t
-mq_req_xattr (xlator_t *, loc_t *, dict_t *);
+mq_req_xattr (xlator_t *, loc_t *, dict_t *, char *);
int32_t
init_quota_priv (xlator_t *);
@@ -117,6 +138,12 @@ mq_set_inode_xattr (xlator_t *, loc_t *);
int
mq_initiate_quota_txn (xlator_t *, loc_t *);
+int
+mq_initiate_quota_blocking_txn (xlator_t *, loc_t *);
+
+int
+mq_create_xattrs_txn (xlator_t *this, loc_t *loc);
+
int32_t
mq_dirty_inode_readdir (call_frame_t *, void *, xlator_t *,
int32_t, int32_t, fd_t *, dict_t *);
@@ -125,6 +152,9 @@ int32_t
mq_reduce_parent_size (xlator_t *, loc_t *, int64_t);
int32_t
+mq_reduce_parent_size_txn (xlator_t *, loc_t *, int64_t);
+
+int32_t
mq_rename_update_newpath (xlator_t *, loc_t *);
int32_t
diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c
index ad3aabda9ba..af7ec1f907f 100644
--- a/xlators/features/marker/src/marker.c
+++ b/xlators/features/marker/src/marker.c
@@ -607,7 +607,7 @@ marker_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
priv = this->private;
if (priv->feature_enabled & GF_QUOTA)
- mq_set_inode_xattr (this, &local->loc);
+ mq_create_xattrs_txn (this, &local->loc);
if (priv->feature_enabled & GF_XTIME)
marker_xtime_update_marks (this, local);
@@ -681,7 +681,7 @@ marker_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
priv = this->private;
if (priv->feature_enabled & GF_QUOTA)
- mq_set_inode_xattr (this, &local->loc);
+ mq_create_xattrs_txn (this, &local->loc);
if (priv->feature_enabled & GF_XTIME)
marker_xtime_update_marks (this, local);
@@ -827,7 +827,7 @@ marker_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
priv = this->private;
if (priv->feature_enabled & GF_QUOTA)
- mq_reduce_parent_size (this, &local->loc, -1);
+ mq_reduce_parent_size_txn (this, &local->loc, -1);
if (priv->feature_enabled & GF_XTIME)
marker_xtime_update_marks (this, local);
@@ -896,7 +896,7 @@ marker_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
if (priv->feature_enabled & GF_QUOTA) {
if (!local->skip_txn)
- mq_reduce_parent_size (this, &local->loc, -1);
+ mq_reduce_parent_size_txn (this, &local->loc, -1);
}
if (priv->feature_enabled & GF_XTIME)
@@ -977,7 +977,7 @@ marker_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
if (priv->feature_enabled & GF_QUOTA) {
if (!local->skip_txn)
- mq_set_inode_xattr (this, &local->loc);
+ mq_create_xattrs_txn (this, &local->loc);
}
@@ -1065,10 +1065,11 @@ marker_rename_done (call_frame_t *frame, void *cookie, xlator_t *this,
frame->root->unique);
}
- mq_reduce_parent_size (this, &oplocal->loc, oplocal->contribution);
+ mq_reduce_parent_size_txn (this, &oplocal->loc, oplocal->contribution);
if (local->loc.inode != NULL) {
- mq_reduce_parent_size (this, &local->loc, local->contribution);
+ mq_reduce_parent_size_txn (this, &local->loc,
+ local->contribution);
}
newloc.inode = inode_ref (oplocal->loc.inode);
@@ -1078,7 +1079,7 @@ marker_rename_done (call_frame_t *frame, void *cookie, xlator_t *this,
newloc.name++;
newloc.parent = inode_ref (local->loc.parent);
- mq_set_inode_xattr (this, &newloc);
+ mq_create_xattrs_txn (this, &newloc);
loc_wipe (&newloc);
@@ -1181,13 +1182,13 @@ marker_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
struct iatt *prenewparent, struct iatt *postnewparent,
dict_t *xdata)
{
- marker_conf_t *priv = NULL;
- marker_local_t *local = NULL;
- marker_local_t *oplocal = NULL;
- call_stub_t *stub = NULL;
- int32_t ret = 0;
- char contri_key [512] = {0, };
- loc_t newloc = {0, };
+ marker_conf_t *priv = NULL;
+ marker_local_t *local = NULL;
+ marker_local_t *oplocal = NULL;
+ call_stub_t *stub = NULL;
+ int32_t ret = 0;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ loc_t newloc = {0, };
local = (marker_local_t *) frame->local;
@@ -1284,10 +1285,11 @@ int32_t
marker_do_rename (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, dict_t *dict, dict_t *xdata)
{
- marker_local_t *local = NULL, *oplocal = NULL;
- char contri_key[512] = {0, };
- int32_t ret = 0;
- int64_t *contribution = 0;
+ marker_local_t *local = NULL;
+ marker_local_t *oplocal = NULL;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ int32_t ret = 0;
+ int64_t *contribution = 0;
local = frame->local;
oplocal = local->oplocal;
@@ -1336,10 +1338,11 @@ marker_get_newpath_contribution (call_frame_t *frame, void *cookie,
xlator_t *this, int32_t op_ret,
int32_t op_errno, dict_t *dict, dict_t *xdata)
{
- marker_local_t *local = NULL, *oplocal = NULL;
- char contri_key[512] = {0, };
- int32_t ret = 0;
- int64_t *contribution = 0;
+ marker_local_t *local = NULL;
+ marker_local_t *oplocal = NULL;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ int32_t ret = 0;
+ int64_t *contribution = 0;
local = frame->local;
oplocal = local->oplocal;
@@ -1403,9 +1406,10 @@ marker_get_oldpath_contribution (call_frame_t *frame, void *cookie,
xlator_t *this, int32_t op_ret,
int32_t op_errno, dict_t *xdata)
{
- marker_local_t *local = NULL, *oplocal = NULL;
- char contri_key[512] = {0, };
- int32_t ret = 0;
+ marker_local_t *local = NULL;
+ marker_local_t *oplocal = NULL;
+ char contri_key[CONTRI_KEY_MAX] = {0, };
+ int32_t ret = 0;
local = frame->local;
oplocal = local->oplocal;
@@ -1764,8 +1768,9 @@ marker_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
priv = this->private;
- if (priv->feature_enabled & GF_QUOTA)
- mq_set_inode_xattr (this, &local->loc);
+ if (priv->feature_enabled & GF_QUOTA) {
+ mq_create_xattrs_txn (this, &local->loc);
+ }
if (priv->feature_enabled & GF_XTIME)
marker_xtime_update_marks (this, local);
@@ -1838,7 +1843,7 @@ marker_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
priv = this->private;
if ((priv->feature_enabled & GF_QUOTA) && (S_ISREG (local->mode))) {
- mq_set_inode_xattr (this, &local->loc);
+ mq_create_xattrs_txn (this, &local->loc);
}
if (priv->feature_enabled & GF_XTIME)
@@ -2706,7 +2711,7 @@ marker_lookup (call_frame_t *frame, xlator_t *this,
goto err;
if ((priv->feature_enabled & GF_QUOTA) && xattr_req)
- mq_req_xattr (this, loc, xattr_req);
+ mq_req_xattr (this, loc, xattr_req, NULL);
wind:
STACK_WIND (frame, marker_lookup_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->lookup, loc, xattr_req);
@@ -2854,7 +2859,7 @@ marker_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
loc.parent = local->loc.inode = inode_ref (fd->inode);
- mq_req_xattr (this, &loc, dict);
+ mq_req_xattr (this, &loc, dict, NULL);
}
STACK_WIND (frame, marker_readdirp_cbk,