12a457
From 1b8f8135c1037b13691ca55da1ebfad8c5bd4a05 Mon Sep 17 00:00:00 2001
12a457
From: vmallika <vmallika@redhat.com>
12a457
Date: Wed, 30 Mar 2016 20:16:32 +0530
12a457
Subject: [PATCH 54/80] marker: build_ancestry in marker
12a457
12a457
This is a backport of http://review.gluster.org/13857
12a457
12a457
* quota-enforcer doesn't execute build_ancestry in the below
12a457
  code path
12a457
    1) Special client (PID < 0)
12a457
    2) unlink
12a457
    3) rename within the same directory
12a457
    4) link within the same directory
12a457
12a457
    In these cases, marker accounting can fail as parent not found.
12a457
    We need to build_ancestry in marker if it doesn't find parent
12a457
    during update txn
12a457
12a457
> Change-Id: Idb7a2906500647baa6d183ba859b15e34769029c
12a457
> BUG: 1320818
12a457
> Signed-off-by: vmallika <vmallika@redhat.com>
12a457
> Reviewed-on: http://review.gluster.org/13857
12a457
> CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
12a457
> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
12a457
> Tested-by: Raghavendra G <rgowdapp@redhat.com>
12a457
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
12a457
> Smoke: Gluster Build System <jenkins@build.gluster.com>
12a457
12a457
Change-Id: I582d0b0e42f8b7a7e52e43f502d6e5c8e97f849e
12a457
BUG: 1318170
12a457
Signed-off-by: vmallika <vmallika@redhat.com>
12a457
Reviewed-on: https://code.engineering.redhat.com/gerrit/71537
12a457
Reviewed-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
12a457
Tested-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
12a457
---
12a457
 xlators/features/marker/src/marker-quota-helper.c |    8 +-
12a457
 xlators/features/marker/src/marker-quota.c        |  168 ++++++++++++++++++--
12a457
 xlators/features/quota/src/quota.c                |    5 +-
12a457
 3 files changed, 162 insertions(+), 19 deletions(-)
12a457
12a457
diff --git a/xlators/features/marker/src/marker-quota-helper.c b/xlators/features/marker/src/marker-quota-helper.c
12a457
index c2268bf..82d45ef 100644
12a457
--- a/xlators/features/marker/src/marker-quota-helper.c
12a457
+++ b/xlators/features/marker/src/marker-quota-helper.c
12a457
@@ -73,7 +73,13 @@ mq_inode_loc_fill (const char *parent_gfid, inode_t *inode, loc_t *loc)
12a457
 
12a457
         this = THIS;
12a457
 
12a457
-        if ((!inode) || (!loc))
12a457
+        if (inode == NULL) {
12a457
+                gf_log_callingfn ("marker", GF_LOG_ERROR, "loc fill failed, "
12a457
+                                  "inode is NULL");
12a457
+                return ret;
12a457
+        }
12a457
+
12a457
+        if (loc == NULL)
12a457
                 return ret;
12a457
 
12a457
         if ((inode) && __is_root_gfid (inode->gfid)) {
12a457
diff --git a/xlators/features/marker/src/marker-quota.c b/xlators/features/marker/src/marker-quota.c
12a457
index 5343a94..d6545da 100644
12a457
--- a/xlators/features/marker/src/marker-quota.c
12a457
+++ b/xlators/features/marker/src/marker-quota.c
12a457
@@ -169,6 +169,109 @@ out:
12a457
         return -1;
12a457
 }
12a457
 
12a457
+int
12a457
+mq_build_ancestry (xlator_t *this, loc_t *loc)
12a457
+{
12a457
+        int32_t               ret            = -1;
12a457
+        fd_t                 *fd             = NULL;
12a457
+        gf_dirent_t           entries;
12a457
+        gf_dirent_t          *entry          = NULL;
12a457
+        dict_t               *xdata          = NULL;
12a457
+        inode_t              *tmp_parent     = NULL;
12a457
+        inode_t              *tmp_inode      = NULL;
12a457
+        inode_t              *linked_inode   = NULL;
12a457
+        quota_inode_ctx_t    *ctx            = NULL;
12a457
+
12a457
+        INIT_LIST_HEAD (&entries.list);
12a457
+
12a457
+        xdata = dict_new ();
12a457
+        if (xdata == NULL) {
12a457
+                gf_log (this->name, GF_LOG_ERROR, "dict_new failed");
12a457
+                ret = -ENOMEM;
12a457
+                goto out;
12a457
+        }
12a457
+
12a457
+        ret = dict_set_int8 (xdata, GET_ANCESTRY_DENTRY_KEY, 1);
12a457
+        if (ret < 0)
12a457
+                goto out;
12a457
+
12a457
+        fd = fd_anonymous (loc->inode);
12a457
+        if (fd == NULL) {
12a457
+                gf_log (this->name, GF_LOG_ERROR, "fd creation failed");
12a457
+                ret = -ENOMEM;
12a457
+                goto out;
12a457
+        }
12a457
+
12a457
+        fd_bind (fd);
12a457
+
12a457
+        ret = syncop_readdirp (this, fd, 131072, 0, &entries, xdata, NULL);
12a457
+        if (ret < 0) {
12a457
+                gf_log (this->name, (-ret == ENOENT || -ret == ESTALE)
12a457
+                        ? GF_LOG_DEBUG:GF_LOG_ERROR, "readdirp failed "
12a457
+                        "for %s: %s", loc->path, strerror (-ret));
12a457
+                goto out;
12a457
+        }
12a457
+
12a457
+        if (list_empty (&entries.list)) {
12a457
+                ret = -1;
12a457
+                goto out;
12a457
+        }
12a457
+
12a457
+        list_for_each_entry (entry, &entries.list, list) {
12a457
+                if (__is_root_gfid (entry->inode->gfid)) {
12a457
+                        tmp_parent = NULL;
12a457
+                } else {
12a457
+                        linked_inode = inode_link (entry->inode, tmp_parent,
12a457
+                                                   entry->d_name,
12a457
+                                                   &entry->d_stat);
12a457
+                        if (linked_inode) {
12a457
+                                tmp_inode = entry->inode;
12a457
+                                entry->inode = linked_inode;
12a457
+                                inode_unref (tmp_inode);
12a457
+                        } else {
12a457
+                                gf_log (this->name, GF_LOG_ERROR,
12a457
+                                        "inode link failed");
12a457
+                                ret = -EINVAL;
12a457
+                                goto out;
12a457
+                        }
12a457
+                }
12a457
+
12a457
+                ctx = mq_inode_ctx_new (entry->inode, this);
12a457
+                if (ctx == NULL) {
12a457
+                        gf_log (this->name, GF_LOG_WARNING, "mq_inode_ctx_new "
12a457
+                                "failed for %s",
12a457
+                                uuid_utoa (entry->inode->gfid));
12a457
+                        ret = -ENOMEM;
12a457
+                        goto out;
12a457
+                }
12a457
+
12a457
+                tmp_parent = entry->inode;
12a457
+        }
12a457
+
12a457
+        if (loc->parent)
12a457
+                inode_unref (loc->parent);
12a457
+
12a457
+        loc->parent = inode_parent (loc->inode, 0, NULL);
12a457
+        if (loc->parent == NULL) {
12a457
+                ret = -1;
12a457
+                goto out;
12a457
+        }
12a457
+
12a457
+        ret = 0;
12a457
+
12a457
+out:
12a457
+        gf_dirent_free (&entries);
12a457
+
12a457
+        if (fd)
12a457
+                fd_unref (fd);
12a457
+
12a457
+        if (xdata)
12a457
+                dict_unref (xdata);
12a457
+
12a457
+        return ret;
12a457
+}
12a457
+
12a457
+
12a457
 /* This function should be used only in inspect_directory and inspect_file
12a457
  * function to heal quota xattrs.
12a457
  * Inode quota feature is introduced in 3.7.
12a457
@@ -1030,13 +1133,8 @@ mq_prevalidate_txn (xlator_t *this, loc_t *origin_loc, loc_t *loc,
12a457
         if (gf_uuid_is_null (loc->gfid))
12a457
                 gf_uuid_copy (loc->gfid, loc->inode->gfid);
12a457
 
12a457
-        if (!loc_is_root(loc) && loc->parent == NULL) {
12a457
+        if (!loc_is_root(loc) && loc->parent == NULL)
12a457
                 loc->parent = inode_parent (loc->inode, 0, NULL);
12a457
-                if (loc->parent == NULL) {
12a457
-                        ret = -1;
12a457
-                        goto out;
12a457
-                }
12a457
-        }
12a457
 
12a457
         ret = mq_inode_ctx_get (loc->inode, this, &ctxtmp);
12a457
         if (ret < 0) {
12a457
@@ -1133,7 +1231,7 @@ _mq_create_xattrs_txn (xlator_t *this, loc_t *origin_loc, struct iatt *buf,
12a457
         if (ret < 0 || status == _gf_true)
12a457
                 goto out;
12a457
 
12a457
-        if (!loc_is_root(&loc)) {
12a457
+        if (!loc_is_root(&loc) && loc.parent) {
12a457
                 contribution = mq_add_new_contribution_node (this, ctx, &loc;;
12a457
                 if (contribution == NULL) {
12a457
                         gf_log (this->name, GF_LOG_WARNING,
12a457
@@ -1211,7 +1309,8 @@ mq_reduce_parent_size_task (void *opaque)
12a457
 
12a457
         ret = mq_inode_loc_fill (NULL, loc->parent, &parent_loc);
12a457
         if (ret < 0) {
12a457
-                gf_log (this->name, GF_LOG_ERROR, "loc fill failed");
12a457
+                gf_log (this->name, GF_LOG_ERROR, "parent_loc fill failed for "
12a457
+                        "child inode %s: ", uuid_utoa (loc->inode->gfid));
12a457
                 goto out;
12a457
         }
12a457
 
12a457
@@ -1290,7 +1389,8 @@ out:
12a457
                          */
12a457
                         ret = mq_inode_ctx_get (parent_loc.inode, this,
12a457
                                                 &parent_ctx);
12a457
-                        mq_set_ctx_dirty_status (parent_ctx, _gf_false);
12a457
+                        if (ret == 0)
12a457
+                                mq_set_ctx_dirty_status (parent_ctx, _gf_false);
12a457
                 } else {
12a457
                         ret = mq_mark_dirty (this, &parent_loc, 0);
12a457
                 }
12a457
@@ -1333,6 +1433,7 @@ mq_reduce_parent_size_txn (xlator_t *this, loc_t *origin_loc,
12a457
                             contri, nlink);
12a457
 out:
12a457
         loc_wipe (&loc;;
12a457
+
12a457
         return ret;
12a457
 }
12a457
 
12a457
@@ -1387,7 +1488,7 @@ mq_initiate_quota_task (void *opaque)
12a457
                  * if one is already in progress for same inode
12a457
                  */
12a457
                 if (status == _gf_true) {
12a457
-                        /* status will alreday set before txn start,
12a457
+                        /* status will already set before txn start,
12a457
                          * so it should not be set in first
12a457
                          * loop iteration
12a457
                          */
12a457
@@ -1397,9 +1498,28 @@ mq_initiate_quota_task (void *opaque)
12a457
                                 goto out;
12a457
                 }
12a457
 
12a457
+                if (child_loc.parent == NULL) {
12a457
+                        ret = mq_build_ancestry (this, &child_loc);
12a457
+                        if (ret < 0 || child_loc.parent == NULL) {
12a457
+                                /* If application performs parallel remove
12a457
+                                 * operations on same set of files/directories
12a457
+                                 * then we may get ENOENT/ESTALE
12a457
+                                 */
12a457
+                                gf_log (this->name,
12a457
+                                        (-ret == ENOENT || -ret == ESTALE)
12a457
+                                        ? GF_LOG_DEBUG:GF_LOG_ERROR,
12a457
+                                        "build ancestry failed for inode %s",
12a457
+                                        uuid_utoa (child_loc.inode->gfid));
12a457
+                                ret = -1;
12a457
+                                goto out;
12a457
+                        }
12a457
+                }
12a457
+
12a457
                 ret = mq_inode_loc_fill (NULL, child_loc.parent, &parent_loc);
12a457
                 if (ret < 0) {
12a457
-                        gf_log (this->name, GF_LOG_ERROR, "loc fill failed");
12a457
+                        gf_log (this->name, GF_LOG_ERROR, "parent_loc fill "
12a457
+                                "failed for child inode %s: ",
12a457
+                                uuid_utoa (child_loc.inode->gfid));
12a457
                         goto out;
12a457
                 }
12a457
 
12a457
@@ -1443,13 +1563,20 @@ mq_initiate_quota_task (void *opaque)
12a457
                       wrong parent as it was holding lock on old parent
12a457
                       so validate parent once the lock is acquired
12a457
 
12a457
-                     For more information on thsi problem, please see
12a457
+                     For more information on this problem, please see
12a457
                      doc for marker_rename in file marker.c
12a457
                 */
12a457
                 contri = mq_get_contribution_node (child_loc.parent, ctx);
12a457
                 if (contri == NULL) {
12a457
                         tmp_parent = inode_parent (child_loc.inode, 0, NULL);
12a457
                         if (tmp_parent == NULL) {
12a457
+                                /* This can happen if application performs
12a457
+                                 * parallel remove operations on same set
12a457
+                                 * of files/directories
12a457
+                                 */
12a457
+                                gf_log (this->name, GF_LOG_WARNING, "parent is "
12a457
+                                        "NULL for inode %s",
12a457
+                                        uuid_utoa (child_loc.inode->gfid));
12a457
                                 ret = -1;
12a457
                                 goto out;
12a457
                         }
12a457
@@ -1481,7 +1608,6 @@ mq_initiate_quota_task (void *opaque)
12a457
                 if (quota_meta_is_null (&delta))
12a457
                         goto out;
12a457
 
12a457
-                prev_dirty = 0;
12a457
                 ret = mq_get_set_dirty (this, &parent_loc, 1, &prev_dirty);
12a457
                 if (ret < 0)
12a457
                         goto out;
12a457
@@ -1502,8 +1628,14 @@ mq_initiate_quota_task (void *opaque)
12a457
 
12a457
                 if (prev_dirty == 0) {
12a457
                         ret = mq_mark_dirty (this, &parent_loc, 0);
12a457
-                        dirty = _gf_false;
12a457
+                } else {
12a457
+                        ret = mq_inode_ctx_get (parent_loc.inode, this,
12a457
+                                                &parent_ctx);
12a457
+                        if (ret == 0)
12a457
+                                mq_set_ctx_dirty_status (parent_ctx, _gf_false);
12a457
                 }
12a457
+                dirty = _gf_false;
12a457
+                prev_dirty = 0;
12a457
 
12a457
                 ret = mq_lock (this, &parent_loc, F_UNLCK);
12a457
                 locked = _gf_false;
12a457
@@ -1534,7 +1666,8 @@ out:
12a457
                          */
12a457
                         ret = mq_inode_ctx_get (parent_loc.inode, this,
12a457
                                                 &parent_ctx);
12a457
-                        mq_set_ctx_dirty_status (parent_ctx, _gf_false);
12a457
+                        if (ret == 0)
12a457
+                                mq_set_ctx_dirty_status (parent_ctx, _gf_false);
12a457
                 } else {
12a457
                         ret = mq_mark_dirty (this, &parent_loc, 0);
12a457
                 }
12a457
@@ -1767,7 +1900,8 @@ out:
12a457
                  * can set the status flag and fix the
12a457
                  * dirty directory
12a457
                  */
12a457
-                mq_set_ctx_dirty_status (ctx, _gf_false);
12a457
+                if (ctx)
12a457
+                        mq_set_ctx_dirty_status (ctx, _gf_false);
12a457
         } else if (dirty) {
12a457
                 mq_mark_dirty (this, loc, 0);
12a457
         }
12a457
@@ -1960,7 +2094,7 @@ mq_xattr_state (xlator_t *this, loc_t *origin_loc, dict_t *dict,
12a457
         inode_contribution_t *contribution    = NULL;
12a457
 
12a457
         ret = mq_prevalidate_txn (this, origin_loc, &loc, &ctx, &buf;;
12a457
-        if (ret < 0)
12a457
+        if (ret < 0 || loc.parent == NULL)
12a457
                 goto out;
12a457
 
12a457
         if (!loc_is_root(&loc)) {
12a457
diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c
12a457
index aaf9cf8..3dcb021 100644
12a457
--- a/xlators/features/quota/src/quota.c
12a457
+++ b/xlators/features/quota/src/quota.c
12a457
@@ -825,7 +825,10 @@ quota_build_ancestry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
12a457
                                 break;
12a457
                 }
12a457
 
12a457
-                GF_ASSERT (&entry->list != &entries->list);
12a457
+                /* Getting assertion here, need to investigate
12a457
+                   comment for now
12a457
+                   GF_ASSERT (&entry->list != &entries->list);
12a457
+                */
12a457
 
12a457
                 quota_add_parent (&parents, entry->d_name, parent->gfid);
12a457
         }
12a457
-- 
12a457
1.7.1
12a457