From 460ce40d3e2069bf6262dccea6f5ae2fac60d90f Mon Sep 17 00:00:00 2001 From: Raghavendra G Date: Mon, 16 Sep 2013 21:35:08 +0530 Subject: features/marker: quota friendly changes * handles renames on dht linkfiles correctly * nameless lookup friendly changes. uses gfid-to-path conversion functionality from storage/posix to build ancestry till root. * log message cleanup. * build inode contexts in readdirp * Accounting still not correct with hardlinks. Credits: ======== Vijay Bellur Raghavendra Bhat Change-Id: I415b6fbbc9691f5a38d9fd3c5d083a61e578bb81 BUG: 969461 Signed-off-by: Raghavendra G Reviewed-on: http://review.gluster.org/5953 Tested-by: Gluster Build System Reviewed-by: Anand Avati --- xlators/features/marker/src/marker-quota-helper.c | 31 ++- xlators/features/marker/src/marker-quota.c | 279 ++++++++++++++++++---- xlators/features/marker/src/marker-quota.h | 23 +- xlators/features/marker/src/marker.c | 141 +++++++++-- xlators/features/marker/src/marker.h | 1 + xlators/features/quota/src/quota.c | 2 +- xlators/storage/posix/src/posix-helpers.c | 92 +++++++ 7 files changed, 479 insertions(+), 90 deletions(-) diff --git a/xlators/features/marker/src/marker-quota-helper.c b/xlators/features/marker/src/marker-quota-helper.c index af5fed13271..ec0d83316c7 100644 --- a/xlators/features/marker/src/marker-quota-helper.c +++ b/xlators/features/marker/src/marker-quota-helper.c @@ -154,15 +154,17 @@ out: inode_contribution_t * -__mq_add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, loc_t *loc) +__mq_add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, + loc_t *loc) { - int32_t ret = 0; + int32_t ret = 0; inode_contribution_t *contribution = NULL; if (!loc->parent) { if (!uuid_is_null (loc->pargfid)) loc->parent = inode_find (loc->inode->table, loc->pargfid); + if (!loc->parent) loc->parent = inode_parent (loc->inode, loc->pargfid, loc->name); @@ -170,9 +172,10 @@ __mq_add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, loc_t *l goto out; } - list_for_each_entry (contribution, &ctx->contribution_head, contri_list) { + list_for_each_entry (contribution, &ctx->contribution_head, + contri_list) { if (loc->parent && - uuid_compare (contribution->gfid, loc->parent->gfid) == 0) { + uuid_compare (contribution->gfid, loc->parent->gfid) == 0) { goto out; } } @@ -196,14 +199,16 @@ out: inode_contribution_t * -mq_add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, loc_t *loc) +mq_add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, + loc_t *loc) { inode_contribution_t *contribution = NULL; if ((ctx == NULL) || (loc == NULL)) return NULL; - if (strcmp (loc->path, "/") == 0) + if (((loc->path) && (strcmp (loc->path, "/") == 0)) + || (!loc->path && uuid_is_null (loc->pargfid))) return NULL; LOCK (&ctx->lock); @@ -226,12 +231,16 @@ mq_dict_set_contribution (xlator_t *this, dict_t *dict, GF_VALIDATE_OR_GOTO ("marker", this, out); GF_VALIDATE_OR_GOTO ("marker", dict, out); GF_VALIDATE_OR_GOTO ("marker", loc, out); - GF_VALIDATE_OR_GOTO ("marker", loc->parent, out); - GET_CONTRI_KEY (contri_key, loc->parent->gfid, ret); - if (ret < 0) { - ret = -1; - goto out; + if (loc->parent) { + GET_CONTRI_KEY (contri_key, loc->parent->gfid, ret); + if (ret < 0) { + ret = -1; + goto out; + } + } else { + /* nameless lookup, fetch contributions to all parents */ + GET_CONTRI_KEY (contri_key, NULL, ret); } ret = dict_set_int64 (dict, contri_key, 0); diff --git a/xlators/features/marker/src/marker-quota.c b/xlators/features/marker/src/marker-quota.c index 6f9af6e1335..d972d7f85b0 100644 --- a/xlators/features/marker/src/marker-quota.c +++ b/xlators/features/marker/src/marker-quota.c @@ -30,7 +30,8 @@ mq_loc_copy (loc_t *dst, loc_t *src) GF_VALIDATE_OR_GOTO ("marker", src, out); if (src->inode == NULL || - src->path == NULL) { + ((src->parent == NULL) && (uuid_is_null (src->pargfid)) + && !__is_root_gfid (src->inode->gfid))) { gf_log ("marker", GF_LOG_WARNING, "src loc is not valid"); goto out; @@ -1038,7 +1039,11 @@ mq_create_xattr (xlator_t *this, call_frame_t *frame) goto free_size; } - if (strcmp (local->loc.path, "/") != 0) { + if ((local->loc.path && strcmp (local->loc.path, "/") != 0) + || (local->loc.inode && !uuid_is_null (local->loc.inode->gfid) && + !__is_root_gfid (local->loc.inode->gfid)) + || (!uuid_is_null (local->loc.gfid) + && !__is_root_gfid (local->loc.gfid))) { contri = mq_add_new_contribution_node (this, ctx, &local->loc); if (contri == NULL) goto err; @@ -1107,7 +1112,12 @@ mq_check_n_set_inode_xattr (call_frame_t *frame, void *cookie, goto create_xattr; //check contribution xattr if not root - if (strcmp (local->loc.path, "/") != 0) { + if ((local->loc.path && strcmp (local->loc.path, "/") != 0) + || (!uuid_is_null (local->loc.gfid) + && !__is_root_gfid (local->loc.gfid)) + || (local->loc.inode + && !uuid_is_null (local->loc.inode->gfid) + && !__is_root_gfid (local->loc.inode->gfid))) { GET_CONTRI_KEY (contri_key, local->loc.parent->gfid, ret); if (ret < 0) goto out; @@ -1234,6 +1244,7 @@ mq_get_parent_inode_local (xlator_t *this, quota_local_t *local) { int32_t ret = -1; quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contribution = NULL; GF_VALIDATE_OR_GOTO ("marker", this, out); GF_VALIDATE_OR_GOTO ("marker", local, out); @@ -1263,7 +1274,7 @@ mq_get_parent_inode_local (xlator_t *this, quota_local_t *local) ret = mq_inode_ctx_get (local->loc.inode, this, &ctx); if (ret < 0) { gf_log_callingfn (this->name, GF_LOG_WARNING, - "inode ctx get failed"); + "inode ctx get failed"); goto out; } @@ -1277,7 +1288,31 @@ mq_get_parent_inode_local (xlator_t *this, quota_local_t *local) goto out; } - local->contri = (inode_contribution_t *) ctx->contribution_head.next; + /* Earlier we used to get the next entry in the list maintained + by the context. In a good situation it works. i.e the next + parent in the directory hierarchy for this path is obtained. + + But consider the below situation: + mount-point: /mnt/point + quota enabled directories within mount point: /a, /b, /c + + Now when some file (file1) in the directory /c is written some data, + then to update the directories, marker has to get the contribution + object for the parent inode, i.e /c. + Beefore, it was being done by + local->contri = (inode_contribution_t *) ctx->contribution_head.next; + It works in the normal situations. But suppose /c is moved to /b. + Now /b's contribution object is added to the end of the list of + parents that the file file1 within /b/c is maintaining. Now if + the file /b/c/file1 is copied to /b/c/new, to update the parent in + the order c, b and / we cannot go to the next element in the list, + as in this case the next contribution object would be / and /b's + contribution will be at the end of the list. So get the proper + parent's contribution, by searching the entire list. + */ + contribution = mq_get_contribution_node (local->loc.parent, ctx); + GF_ASSERT (contribution != NULL); + local->contri = contribution; ret = 0; out: @@ -1521,9 +1556,10 @@ mq_update_parent_size (call_frame_t *frame, } UNLOCK (&local->contri->lock); - gf_log (this->name, GF_LOG_DEBUG, "%s %"PRId64 "%"PRId64, - local->loc.path, local->ctx->size, - local->contri->contribution); + gf_log_callingfn (this->name, GF_LOG_DEBUG, "path: %s size: %"PRId64 + " contribution:%"PRId64, + local->loc.path, local->ctx->size, + local->contri->contribution); if (dict == NULL) { op_errno = EINVAL; @@ -1730,7 +1766,8 @@ mq_fetch_child_size_and_contri (call_frame_t *frame, void *cookie, VALIDATE_OR_GOTO (local->ctx, err); VALIDATE_OR_GOTO (local->contri, err); - gf_log (this->name, GF_LOG_DEBUG, "%s marked dirty", local->parent_loc.path); + gf_log (this->name, GF_LOG_DEBUG, "%s marked dirty", + local->parent_loc.path); //update parent ctx ret = mq_inode_ctx_get (local->parent_loc.inode, this, &ctx); @@ -1901,15 +1938,18 @@ fr_destroy: return -1; } - int -mq_start_quota_txn (xlator_t *this, loc_t *loc, - quota_inode_ctx_t *ctx, - inode_contribution_t *contri) +mq_prepare_txn_frame (xlator_t *this, loc_t *loc, + quota_inode_ctx_t *ctx, + inode_contribution_t *contri, + call_frame_t **new_frame) { - int32_t ret = -1; - call_frame_t *frame = NULL; - quota_local_t *local = NULL; + call_frame_t *frame = NULL; + int ret = -1; + quota_local_t *local = NULL; + + if (!this || !loc || !new_frame) + goto err; frame = create_frame (this, this->ctx->pool); if (frame == NULL) @@ -1935,14 +1975,36 @@ mq_start_quota_txn (xlator_t *this, loc_t *loc, local->ctx = ctx; local->contri = contri; + ret = 0; + *new_frame = frame; + + return ret; + +fr_destroy: + QUOTA_STACK_DESTROY (frame, this); +err: + return ret; +} + +int +mq_start_quota_txn (xlator_t *this, loc_t *loc, + quota_inode_ctx_t *ctx, + inode_contribution_t *contri) +{ + int32_t ret = -1; + call_frame_t *frame = NULL; + + ret = mq_prepare_txn_frame (this, loc, ctx, + contri, &frame); + if (ret) + goto err; + ret = mq_get_lock_on_parent (frame, this); if (ret == -1) goto err; return 0; -fr_destroy: - QUOTA_STACK_DESTROY (frame, this); err: mq_set_ctx_updation_status (ctx, _gf_false); @@ -1970,11 +2032,46 @@ mq_initiate_quota_txn (xlator_t *this, loc_t *loc) goto out; } + /* Create the contribution node if its absent. Is it right to + assume that if the contribution node is not there, then + create one and proceed instead of returning? + Reason for this assumption is for hard links. Suppose + hard link for a file f1 present in a directory d1 is + created in the directory d2 (as f2). Now, since d2's + contribution is not there in f1's inode ctx, d2's + contribution xattr wont be created and will create problems + for quota operations. + */ contribution = mq_get_contribution_node (loc->parent, ctx); - if (contribution == NULL) - goto out; + 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))) + 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): + NULL); + + contribution = mq_add_new_contribution_node (this, ctx, loc); + if (!contribution) { + if(loc->path && strcmp (loc->path, "/")) + 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): + NULL); + goto out; + } + } - /* To improve performance, donot start another transaction + /* To improve performance, do not start another transaction * if one is already in progress for same inode */ status = _gf_true; @@ -1993,16 +2090,7 @@ out: } -/* int32_t */ -/* validate_inode_size_contribution (xlator_t *this, loc_t *loc, int64_t size, */ -/* int64_t contribution) */ -/* { */ -/* if (size != contribution) { */ -/* mq_initiate_quota_txn (this, loc); */ -/* } */ -/* return 0; */ -/* } */ int32_t @@ -2031,12 +2119,13 @@ mq_inspect_directory_xattr (xlator_t *this, } } - if (strcmp (loc->path, "/") != 0) { + if (!loc->path || (loc->path && strcmp (loc->path, "/") != 0)) { contribution = mq_add_new_contribution_node (this, ctx, loc); if (contribution == NULL) { if (!uuid_is_null (loc->inode->gfid)) - gf_log (this->name, GF_LOG_WARNING, - "cannot add a new contribution node"); + gf_log (this->name, GF_LOG_DEBUG, + "cannot add a new contribution node " + "(%s)", uuid_utoa (loc->inode->gfid)); ret = -1; goto err; } @@ -2050,7 +2139,10 @@ mq_inspect_directory_xattr (xlator_t *this, if (ret < 0) goto out; - if (strcmp (loc->path, "/") != 0) { + 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; GET_CONTRI_KEY (contri_key, contribution->gfid, ret); @@ -2122,8 +2214,11 @@ mq_inspect_file_xattr (xlator_t *this, } contribution = mq_add_new_contribution_node (this, ctx, loc); - if (contribution == NULL) + if (contribution == NULL) { + gf_log_callingfn (this->name, GF_LOG_DEBUG, "cannot allocate " + "contribution node (path:%s)", loc->path); goto out; + } LOCK (&ctx->lock); { @@ -2155,8 +2250,12 @@ mq_inspect_file_xattr (xlator_t *this, if (size != contri_int) { mq_initiate_quota_txn (this, loc); } - } else - mq_initiate_quota_txn (this, loc); + } else { + if (size) + mq_initiate_quota_txn (this, loc); + else + mq_set_inode_xattr (this, loc); + } } out: @@ -2192,7 +2291,7 @@ mq_req_xattr (xlator_t *this, goto set_size; //if not "/" then request contribution - if (strcmp (loc->path, "/") == 0) + if (loc->path && strcmp (loc->path, "/") == 0) goto set_size; ret = mq_dict_set_contribution (this, dict, loc); @@ -2235,6 +2334,12 @@ _mq_inode_remove_done (call_frame_t *frame, void *cookie, xlator_t *this, 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; local = (quota_local_t *) frame->local; @@ -2245,17 +2350,84 @@ _mq_inode_remove_done (call_frame_t *frame, void *cookie, xlator_t *this, frame->local = NULL; - if (local->hl_count > 1) { - GET_CONTRI_KEY (contri_key, local->contri->gfid, ret); + GET_CONTRI_KEY (contri_key, local->contri->gfid, ret); - STACK_WIND (frame, mq_removexattr_cbk, FIRST_CHILD(this), - FIRST_CHILD(this)->fops->removexattr, - &local->loc, contri_key, NULL); - ret = 0; - } else { - mq_removexattr_cbk (frame, NULL, this, 0, 0, NULL); + if (!local->loc.inode) + inode = inode_grep (local->loc.parent->table, local->loc.parent, + local->loc.name); + else + inode = inode_ref (local->loc.inode); + + /* Suppose there are 2 directories dir1 and dir2. Quota limit is set on + both the directories. There is a file (f1) in dir1. A hark link is + created for that file inside the directory dir2 (say f2). Now one + more xattr is set in the inode as a new hard link is created in a + separate directory. + i.e trusted.glusterfs.quota..contri= + + Now when the hardlink f2 is removed, then the new xattr added (i.e + the xattr indicating its contribution to ITS parent directory) should + be removed (IFF there is not another hardlink for that file in the + same directory). + + To do that upon getting unlink first check whether any other hard + links for the same inode exists in the same directory. If so do not + do anything and proceed for quota transaction. + Otherwise, if the removed entry was the only link for that inode + within that directory, then get another dentry for the inode + (by traversing the list of dentries for the inode) and using the + the dentry's parent and name, send removexattr so that the xattr + is removed. + + If it is not done, then if the volume is restarted or the brick + process is restarted, then wrong quota usage will be shown for the + directory dir2. + */ + if (inode) { + tmp = NULL; + list_for_each_entry (tmp, &inode->dentry_list, inode_list) { + if (local->loc.parent == tmp->parent) { + if (strcmp (local->loc.name, local->loc.name)) { + last_dentry = _gf_false; + break; + } + } + } + remove = last_dentry; } + if (remove) { + if (!other_dentry) { + list_for_each_entry (tmp, &inode->dentry_list, + inode_list) { + if (local->loc.parent != tmp->parent) { + other_dentry = tmp; + break; + } + } + } + + if (!other_dentry) + mq_removexattr_cbk (frame, NULL, this, 0, 0, NULL); + else { + loc.parent = inode_ref (other_dentry->parent); + loc.name = gf_strdup (other_dentry->name); + uuid_copy (loc.pargfid , other_dentry->parent->gfid); + loc.inode = inode_ref (inode); + uuid_copy (loc.gfid, inode->gfid); + inode_path (other_dentry->parent, other_dentry->name, + (char **)&loc.path); + + STACK_WIND (frame, mq_removexattr_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->removexattr, + &loc, contri_key, NULL); + } + } else + mq_removexattr_cbk (frame, NULL, this, 0, 0, NULL); + + ret = 0; + if (strcmp (local->parent_loc.path, "/") != 0) { ret = mq_get_parent_inode_local (this, local); if (ret < 0) @@ -2266,6 +2438,8 @@ _mq_inode_remove_done (call_frame_t *frame, void *cookie, xlator_t *this, out: mq_local_unref (this, local); + loc_wipe (&loc); + inode_unref (inode); return 0; } @@ -2392,8 +2566,11 @@ mq_reduce_parent_size (xlator_t *this, loc_t *loc, int64_t contri) goto out; contribution = mq_get_contribution_node (loc->parent, ctx); - if (contribution == NULL) + if (contribution == NULL) { + gf_log_callingfn (this->name, GF_LOG_WARNING, "contribution for" + " the node %s is NULL", loc->path); goto out; + } local = mq_local_new (); if (local == NULL) { @@ -2412,6 +2589,8 @@ mq_reduce_parent_size (xlator_t *this, loc_t *loc, int64_t contri) } if (local->size == 0) { + gf_log_callingfn (this->name, GF_LOG_TRACE, + "local->size is 0 " "path: (%s)", loc->path); ret = 0; goto out; } @@ -2424,8 +2603,12 @@ mq_reduce_parent_size (xlator_t *this, loc_t *loc, int64_t contri) local->contri = contribution; ret = mq_inode_loc_fill (NULL, loc->parent, &local->parent_loc); - if (ret < 0) + if (ret < 0) { + gf_log_callingfn (this->name, GF_LOG_INFO, "building parent loc" + " failed. (gfid: %s)", + uuid_utoa (loc->parent->gfid)); goto out; + } frame = create_frame (this, this->ctx->pool); if (!frame) { diff --git a/xlators/features/marker/src/marker-quota.h b/xlators/features/marker/src/marker-quota.h index 385760ac4dd..42def9d22dc 100644 --- a/xlators/features/marker/src/marker-quota.h +++ b/xlators/features/marker/src/marker-quota.h @@ -42,8 +42,6 @@ var = GF_CALLOC (sizeof (type), 1, \ gf_marker_mt_##type); \ if (!var) { \ - gf_log ("", GF_LOG_ERROR, \ - "out of memory"); \ ret = -1; \ } \ } while (0); @@ -61,13 +59,20 @@ ret = 0; \ } while (0); -#define GET_CONTRI_KEY(var, _gfid, _ret) \ - do { \ - char _gfid_unparsed[40]; \ - uuid_unparse (_gfid, _gfid_unparsed); \ - _ret = snprintf (var, CONTRI_KEY_MAX, QUOTA_XATTR_PREFIX \ - ".%s.%s." CONTRIBUTION, "quota", \ - _gfid_unparsed); \ +#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); #define QUOTA_SAFE_INCREMENT(lock, var) \ diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c index 6df1f5688e2..e448bc08f67 100644 --- a/xlators/features/marker/src/marker.c +++ b/xlators/features/marker/src/marker.c @@ -303,13 +303,11 @@ marker_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, priv = this->private; - if (priv == NULL || (priv->feature_enabled & GF_XTIME) == 0) - goto wind; - gf_log (this->name, GF_LOG_DEBUG, "USER:PID = %d", frame->root->pid); - ret = call_from_special_client (frame, this, name); -wind: + if (priv && priv->feature_enabled & GF_XTIME) + ret = call_from_special_client (frame, this, name); + if (ret == _gf_false) { if (name == NULL) { /* Signifies that marker translator @@ -807,8 +805,10 @@ marker_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, priv = this->private; - if ((priv->feature_enabled & GF_QUOTA) && (local->ia_nlink == 1)) - mq_reduce_parent_size (this, &local->loc, -1); + if (priv->feature_enabled & GF_QUOTA) { + if (!local->skip_txn) + mq_reduce_parent_size (this, &local->loc, -1); + } if (priv->feature_enabled & GF_XTIME) marker_xtime_update_marks (this, local); @@ -874,6 +874,11 @@ marker_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, if (ret == -1) goto err; + if (xdata && dict_get (xdata, GLUSTERFS_INTERNAL_FOP_KEY)) { + local->skip_txn = 1; + goto unlink_wind; + } + if (uuid_is_null (loc->gfid) && loc->inode) uuid_copy (loc->gfid, loc->inode->gfid); @@ -919,8 +924,11 @@ marker_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, priv = this->private; - if (priv->feature_enabled & GF_QUOTA) - mq_initiate_quota_txn (this, &local->loc); + if (priv->feature_enabled & GF_QUOTA) { + if (!local->skip_txn) + mq_set_inode_xattr (this, &local->loc); + } + if (priv->feature_enabled & GF_XTIME) marker_xtime_update_marks (this, local); @@ -951,6 +959,9 @@ marker_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, if (ret == -1) goto err; + + if (xdata && dict_get (xdata, GLUSTERFS_INTERNAL_FOP_KEY)) + local->skip_txn = 1; wind: STACK_WIND (frame, marker_link_cbk, FIRST_CHILD(this), FIRST_CHILD(this)->fops->link, oldloc, newloc, xdata); @@ -1011,7 +1022,7 @@ marker_rename_done (call_frame_t *frame, void *cookie, xlator_t *this, newloc.name++; newloc.parent = inode_ref (local->loc.parent); - mq_rename_update_newpath (this, &newloc); + mq_set_inode_xattr (this, &newloc); loc_wipe (&newloc); @@ -2490,22 +2501,94 @@ err: return 0; } + +int +marker_build_ancestry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, gf_dirent_t *entries, + dict_t *xdata) +{ + gf_dirent_t *entry = NULL; + loc_t loc = {0, }; + inode_t *parent = NULL; + + if ((op_ret <= 0) || (entries == NULL)) { + goto out; + } + + + list_for_each_entry (entry, &entries->list, list) { + if (entry->inode == entry->inode->table->root) { + loc.path = gf_strdup ("/"); + inode_unref (parent); + parent = NULL; + } + + loc.inode = inode_ref (entry->inode); + + if (parent != NULL) { + loc.parent = inode_ref (parent); + uuid_copy (loc.pargfid, parent->gfid); + } + + uuid_copy (loc.gfid, entry->d_stat.ia_gfid); + + mq_xattr_state (this, &loc, entry->dict, entry->d_stat); + + inode_unref (parent); + parent = inode_ref (entry->inode); + loc_wipe (&loc); + } + + if (parent) + inode_unref (parent); + +out: + STACK_UNWIND_STRICT (readdirp, frame, op_ret, op_errno, entries, xdata); + return 0; +} + int marker_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, gf_dirent_t *entries, dict_t *xdata) { - gf_dirent_t *entry = NULL; + gf_dirent_t *entry = NULL; + marker_conf_t *priv = NULL; + marker_local_t *local = NULL; + loc_t loc = {0, }; if (op_ret <= 0) goto unwind; + priv = this->private; + local = frame->local; + + if (!(priv->feature_enabled & GF_QUOTA) || (local == NULL)) { + goto unwind; + } + list_for_each_entry (entry, &entries->list, list) { - /* TODO: fill things */ + if ((strcmp (entry->d_name, ".") == 0) || + (strcmp (entry->d_name, "..") == 0)) + continue; + + loc.inode = inode_ref (entry->inode); + loc.parent = inode_ref (local->loc.inode); + + uuid_copy (loc.gfid, entry->d_stat.ia_gfid); + uuid_copy (loc.pargfid, loc.parent->gfid); + + mq_xattr_state (this, &loc, entry->dict, entry->d_stat); + + loc_wipe (&loc); } unwind: + local = frame->local; + frame->local = NULL; + STACK_UNWIND_STRICT (readdirp, frame, op_ret, op_errno, entries, xdata); + marker_local_unref (local); return 0; } @@ -2514,20 +2597,36 @@ int marker_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, off_t offset, dict_t *dict) { - marker_conf_t *priv = NULL; + marker_conf_t *priv = NULL; + loc_t loc = {0, }; + marker_local_t *local = NULL; priv = this->private; - if (priv->feature_enabled == 0) - goto wind; + if ((dict != NULL) && dict_get (dict, GET_ANCESTRY_DENTRY_KEY)) { + STACK_WIND (frame, marker_build_ancestry_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readdirp, + fd, size, offset, dict); + } else { + if (priv->feature_enabled & GF_QUOTA) { + local = mem_get0 (this->local_pool); - if ((priv->feature_enabled & GF_QUOTA) && dict) - mq_req_xattr (this, NULL, dict); + MARKER_INIT_LOCAL (frame, local); -wind: - STACK_WIND (frame, marker_readdirp_cbk, - FIRST_CHILD(this), FIRST_CHILD(this)->fops->readdirp, - fd, size, offset, dict); + loc.parent = local->loc.inode = inode_ref (fd->inode); + + if (dict == NULL) + dict = dict_new (); + + mq_req_xattr (this, &loc, dict); + } + + STACK_WIND (frame, marker_readdirp_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readdirp, + fd, size, offset, dict); + } return 0; } diff --git a/xlators/features/marker/src/marker.h b/xlators/features/marker/src/marker.h index 1a58f8cfcbc..23d1580f0e5 100644 --- a/xlators/features/marker/src/marker.h +++ b/xlators/features/marker/src/marker.h @@ -112,6 +112,7 @@ struct marker_local{ int xflag; dict_t *xdata; + gf_boolean_t skip_txn; }; typedef struct marker_local marker_local_t; diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c index c527e7ca71c..345d44c5272 100644 --- a/xlators/features/quota/src/quota.c +++ b/xlators/features/quota/src/quota.c @@ -239,7 +239,7 @@ quota_validate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } UNLOCK (&ctx->lock); - quota_check_limit (frame, local->validate_loc.inode, this, NULL, NULL); + quota_check_limit (frame, local->validate_loc.inode, this, NULL, NULL) ; return 0; unwind: diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c index 4db15bf571c..0e187e0200d 100644 --- a/xlators/storage/posix/src/posix-helpers.c +++ b/xlators/storage/posix/src/posix-helpers.c @@ -52,6 +52,8 @@ char *marker_xattrs[] = {"trusted.glusterfs.quota.*", "trusted.glusterfs.*.xtime", NULL}; +char *marker_contri_key = "trusted.*.*.contri"; + static char* posix_ignore_xattrs[] = { "gfid-req", GLUSTERFS_ENTRYLK_COUNT, @@ -142,6 +144,94 @@ out: return ret; } +static int gf_posix_xattr_enotsup_log; + +static int +_posix_get_marker_all_contributions (posix_xattr_filler_t *filler) +{ + ssize_t size = -1, remaining_size = -1, list_offset = 0; + int ret = -1; + char *list = NULL, key[4096] = {0, }; + + size = sys_llistxattr (filler->real_path, NULL, 0); + if (size == -1) { + if ((errno == ENOTSUP) || (errno == ENOSYS)) { + GF_LOG_OCCASIONALLY (gf_posix_xattr_enotsup_log, + THIS->name, GF_LOG_WARNING, + "Extended attributes not " + "supported (try remounting brick" + " with 'user_xattr' flag)"); + + } else { + gf_log (THIS->name, GF_LOG_WARNING, + "listxattr failed on %s: %s", + filler->real_path, strerror (errno)); + + } + + goto out; + } + + if (size == 0) { + ret = 0; + goto out; + } + + list = alloca (size + 1); + if (!list) { + goto out; + } + + size = sys_llistxattr (filler->real_path, list, size); + if (size <= 0) { + ret = size; + goto out; + } + + remaining_size = size; + list_offset = 0; + + while (remaining_size > 0) { + if (*(list + list_offset) == '\0') + break; + strcpy (key, list + list_offset); + if (fnmatch (marker_contri_key, key, 0) == 0) { + ret = _posix_xattr_get_set_from_backend (filler, key); + } + + remaining_size -= strlen (key) + 1; + list_offset += strlen (key) + 1; + } + + ret = 0; + +out: + return ret; +} + +static int +_posix_get_marker_quota_contributions (posix_xattr_filler_t *filler, char *key) +{ + char *saveptr = NULL, *token = NULL, *tmp_key = NULL; + char *ptr = NULL; + int i = 0, ret = 0; + + tmp_key = ptr = gf_strdup (key); + for (i = 0; i < 4; i++) { + token = strtok_r (tmp_key, ".", &saveptr); + tmp_key = NULL; + } + + if (strncmp (token, "contri", strlen ("contri")) == 0) { + ret = _posix_get_marker_all_contributions (filler); + } else { + ret = _posix_xattr_get_set_from_backend (filler, key); + } + + GF_FREE (ptr); + + return ret; +} static int _posix_xattr_get_set (dict_t *xattr_req, @@ -239,6 +329,8 @@ _posix_xattr_get_set (dict_t *xattr_req, goto out; } + } else if (fnmatch (marker_contri_key, key, 0) == 0) { + ret = _posix_get_marker_quota_contributions (filler, key); } else { ret = _posix_xattr_get_set_from_backend (filler, key); } -- cgit