9ae3f9
From 54d4ea44fec96560aad9c41f7e4f5aad164ffb8b Mon Sep 17 00:00:00 2001
9ae3f9
From: Ravishankar N <ravishankar@redhat.com>
9ae3f9
Date: Fri, 5 Jun 2020 14:14:15 +0530
9ae3f9
Subject: [PATCH 424/449] afr: make heal info lockless
9ae3f9
9ae3f9
Changes in locks xlator:
9ae3f9
Added support for per-domain inodelk count requests.
9ae3f9
Caller needs to set GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS key in the
9ae3f9
dict and then set each key with name
9ae3f9
'GLUSTERFS_INODELK_DOM_PREFIX:<domain name>'.
9ae3f9
In the response dict, the xlator will send the per domain count as
9ae3f9
values for each of these keys.
9ae3f9
9ae3f9
Changes in AFR:
9ae3f9
Replaced afr_selfheal_locked_inspect() with afr_lockless_inspect(). Logic has
9ae3f9
been added to make the latter behave same as the former, thus not
9ae3f9
breaking the current heal info output behaviour.
9ae3f9
9ae3f9
> Upstream patch: https://review.gluster.org/#/c/glusterfs/+/23771/
9ae3f9
> fixes: bz#1774011
9ae3f9
> Change-Id: Ie9e83c162aa77f44a39c2ba7115de558120ada4d
9ae3f9
9ae3f9
BUG: 1721355
9ae3f9
Change-Id: I8ed4b504880b19e00068312efd90cd0706787404
9ae3f9
Signed-off-by: Ravishankar N <ravishankar@redhat.com>
9ae3f9
Reviewed-on: https://code.engineering.redhat.com/gerrit/202490
9ae3f9
Tested-by: RHGS Build Bot <nigelb@redhat.com>
9ae3f9
Reviewed-by: Karthik Subrahmanya <ksubrahm@redhat.com>
9ae3f9
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
9ae3f9
---
9ae3f9
 heal/src/glfs-heal.c                           |  17 +-
9ae3f9
 libglusterfs/src/glusterfs/glusterfs.h         |   2 +
9ae3f9
 xlators/cluster/afr/src/afr-common.c           | 367 +++++++++++--------------
9ae3f9
 xlators/cluster/afr/src/afr-self-heal-common.c |  43 ++-
9ae3f9
 xlators/cluster/afr/src/afr-self-heal.h        |   3 +-
9ae3f9
 xlators/features/locks/src/common.h            |   4 +
9ae3f9
 xlators/features/locks/src/locks.h             |   8 +
9ae3f9
 xlators/features/locks/src/posix.c             | 117 +++++++-
9ae3f9
 8 files changed, 338 insertions(+), 223 deletions(-)
9ae3f9
9ae3f9
diff --git a/heal/src/glfs-heal.c b/heal/src/glfs-heal.c
9ae3f9
index 125b12c..5af9e31 100644
9ae3f9
--- a/heal/src/glfs-heal.c
9ae3f9
+++ b/heal/src/glfs-heal.c
9ae3f9
@@ -775,7 +775,8 @@ static int
9ae3f9
 glfsh_process_entries(xlator_t *xl, fd_t *fd, gf_dirent_t *entries,
9ae3f9
                       uint64_t *offset, num_entries_t *num_entries,
9ae3f9
                       print_status glfsh_print_status,
9ae3f9
-                      gf_boolean_t ignore_dirty, glfsh_fail_mode_t mode)
9ae3f9
+                      gf_boolean_t ignore_dirty, glfsh_fail_mode_t mode,
9ae3f9
+                      dict_t *xattr_req)
9ae3f9
 {
9ae3f9
     gf_dirent_t *entry = NULL;
9ae3f9
     gf_dirent_t *tmp = NULL;
9ae3f9
@@ -807,7 +808,7 @@ glfsh_process_entries(xlator_t *xl, fd_t *fd, gf_dirent_t *entries,
9ae3f9
 
9ae3f9
         gf_uuid_parse(entry->d_name, gfid);
9ae3f9
         gf_uuid_copy(loc.gfid, gfid);
9ae3f9
-        ret = syncop_getxattr(this, &loc, &dict, GF_HEAL_INFO, NULL, NULL);
9ae3f9
+        ret = syncop_getxattr(this, &loc, &dict, GF_HEAL_INFO, xattr_req, NULL);
9ae3f9
         if (ret) {
9ae3f9
             if ((mode != GLFSH_MODE_CONTINUE_ON_ERROR) && (ret == -ENOTCONN))
9ae3f9
                 goto out;
9ae3f9
@@ -876,19 +877,19 @@ glfsh_crawl_directory(glfs_t *fs, xlator_t *top_subvol, loc_t *rootloc,
9ae3f9
         if (heal_op == GF_SHD_OP_INDEX_SUMMARY) {
9ae3f9
             ret = glfsh_process_entries(readdir_xl, fd, &entries, &offset,
9ae3f9
                                         num_entries, glfsh_print_heal_status,
9ae3f9
-                                        ignore, mode);
9ae3f9
+                                        ignore, mode, xattr_req);
9ae3f9
             if (ret < 0)
9ae3f9
                 goto out;
9ae3f9
         } else if (heal_op == GF_SHD_OP_SPLIT_BRAIN_FILES) {
9ae3f9
             ret = glfsh_process_entries(readdir_xl, fd, &entries, &offset,
9ae3f9
                                         num_entries, glfsh_print_spb_status,
9ae3f9
-                                        ignore, mode);
9ae3f9
+                                        ignore, mode, xattr_req);
9ae3f9
             if (ret < 0)
9ae3f9
                 goto out;
9ae3f9
         } else if (heal_op == GF_SHD_OP_HEAL_SUMMARY) {
9ae3f9
             ret = glfsh_process_entries(readdir_xl, fd, &entries, &offset,
9ae3f9
                                         num_entries, glfsh_print_summary_status,
9ae3f9
-                                        ignore, mode);
9ae3f9
+                                        ignore, mode, xattr_req);
9ae3f9
             if (ret < 0)
9ae3f9
                 goto out;
9ae3f9
         } else if (heal_op == GF_SHD_OP_SBRAIN_HEAL_FROM_BRICK) {
9ae3f9
@@ -897,7 +898,7 @@ glfsh_crawl_directory(glfs_t *fs, xlator_t *top_subvol, loc_t *rootloc,
9ae3f9
         } else if (heal_op == GF_SHD_OP_GRANULAR_ENTRY_HEAL_ENABLE) {
9ae3f9
             ret = glfsh_process_entries(readdir_xl, fd, &entries, &offset,
9ae3f9
                                         num_entries, glfsh_heal_status_boolean,
9ae3f9
-                                        ignore, mode);
9ae3f9
+                                        ignore, mode, xattr_req);
9ae3f9
             if (ret < 0)
9ae3f9
                 goto out;
9ae3f9
         }
9ae3f9
@@ -951,6 +952,10 @@ glfsh_print_pending_heals_type(glfs_t *fs, xlator_t *top_subvol, loc_t *rootloc,
9ae3f9
     int32_t op_errno = 0;
9ae3f9
     gf_boolean_t ignore = _gf_false;
9ae3f9
 
9ae3f9
+    ret = dict_set_str(xattr_req, "index-vgfid", vgfid);
9ae3f9
+    if (ret)
9ae3f9
+        return ret;
9ae3f9
+
9ae3f9
     if (!strcmp(vgfid, GF_XATTROP_DIRTY_GFID))
9ae3f9
         ignore = _gf_true;
9ae3f9
 
9ae3f9
diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h
9ae3f9
index 3b594c0..177a020 100644
9ae3f9
--- a/libglusterfs/src/glusterfs/glusterfs.h
9ae3f9
+++ b/libglusterfs/src/glusterfs/glusterfs.h
9ae3f9
@@ -217,6 +217,8 @@ enum gf_internal_fop_indicator {
9ae3f9
 #define GLUSTERFS_POSIXLK_COUNT "glusterfs.posixlk-count"
9ae3f9
 #define GLUSTERFS_PARENT_ENTRYLK "glusterfs.parent-entrylk"
9ae3f9
 #define GLUSTERFS_INODELK_DOM_COUNT "glusterfs.inodelk-dom-count"
9ae3f9
+#define GLUSTERFS_INODELK_DOM_PREFIX "glusterfs.inodelk-dom-prefix"
9ae3f9
+#define GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS "glusterfs.multi-dom-lk-cnt-req"
9ae3f9
 #define GFID_TO_PATH_KEY "glusterfs.gfid2path"
9ae3f9
 #define GF_XATTR_STIME_PATTERN "trusted.glusterfs.*.stime"
9ae3f9
 #define GF_XATTR_XTIME_PATTERN "trusted.glusterfs.*.xtime"
9ae3f9
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c
9ae3f9
index 59710aa..c355ec5 100644
9ae3f9
--- a/xlators/cluster/afr/src/afr-common.c
9ae3f9
+++ b/xlators/cluster/afr/src/afr-common.c
9ae3f9
@@ -5908,259 +5908,218 @@ out:
9ae3f9
     return _gf_true;
9ae3f9
 }
9ae3f9
 
9ae3f9
-int
9ae3f9
-afr_selfheal_locked_metadata_inspect(call_frame_t *frame, xlator_t *this,
9ae3f9
-                                     inode_t *inode, gf_boolean_t *msh,
9ae3f9
-                                     unsigned char *pending)
9ae3f9
+static dict_t *
9ae3f9
+afr_set_heal_info(char *status)
9ae3f9
 {
9ae3f9
+    dict_t *dict = NULL;
9ae3f9
     int ret = -1;
9ae3f9
-    unsigned char *locked_on = NULL;
9ae3f9
-    unsigned char *sources = NULL;
9ae3f9
-    unsigned char *sinks = NULL;
9ae3f9
-    unsigned char *healed_sinks = NULL;
9ae3f9
-    unsigned char *undid_pending = NULL;
9ae3f9
-    struct afr_reply *locked_replies = NULL;
9ae3f9
-
9ae3f9
-    afr_private_t *priv = this->private;
9ae3f9
 
9ae3f9
-    locked_on = alloca0(priv->child_count);
9ae3f9
-    sources = alloca0(priv->child_count);
9ae3f9
-    sinks = alloca0(priv->child_count);
9ae3f9
-    healed_sinks = alloca0(priv->child_count);
9ae3f9
-    undid_pending = alloca0(priv->child_count);
9ae3f9
+    dict = dict_new();
9ae3f9
+    if (!dict) {
9ae3f9
+        ret = -ENOMEM;
9ae3f9
+        goto out;
9ae3f9
+    }
9ae3f9
 
9ae3f9
-    locked_replies = alloca0(sizeof(*locked_replies) * priv->child_count);
9ae3f9
+    ret = dict_set_dynstr_sizen(dict, "heal-info", status);
9ae3f9
+    if (ret)
9ae3f9
+        gf_msg("", GF_LOG_WARNING, -ret, AFR_MSG_DICT_SET_FAILED,
9ae3f9
+               "Failed to set heal-info key to "
9ae3f9
+               "%s",
9ae3f9
+               status);
9ae3f9
+out:
9ae3f9
+    /* Any error other than EINVAL, dict_set_dynstr frees status */
9ae3f9
+    if (ret == -ENOMEM || ret == -EINVAL) {
9ae3f9
+        GF_FREE(status);
9ae3f9
+    }
9ae3f9
 
9ae3f9
-    ret = afr_selfheal_inodelk(frame, this, inode, this->name, LLONG_MAX - 1, 0,
9ae3f9
-                               locked_on);
9ae3f9
-    {
9ae3f9
-        if (ret == 0) {
9ae3f9
-            /* Not a single lock */
9ae3f9
-            ret = -afr_final_errno(frame->local, priv);
9ae3f9
-            if (ret == 0)
9ae3f9
-                ret = -ENOTCONN; /* all invalid responses */
9ae3f9
-            goto out;
9ae3f9
-        }
9ae3f9
-        ret = __afr_selfheal_metadata_prepare(
9ae3f9
-            frame, this, inode, locked_on, sources, sinks, healed_sinks,
9ae3f9
-            undid_pending, locked_replies, pending);
9ae3f9
-        *msh = afr_decide_heal_info(priv, sources, ret);
9ae3f9
+    if (ret && dict) {
9ae3f9
+        dict_unref(dict);
9ae3f9
+        dict = NULL;
9ae3f9
     }
9ae3f9
-    afr_selfheal_uninodelk(frame, this, inode, this->name, LLONG_MAX - 1, 0,
9ae3f9
-                           locked_on);
9ae3f9
-out:
9ae3f9
-    if (locked_replies)
9ae3f9
-        afr_replies_wipe(locked_replies, priv->child_count);
9ae3f9
-    return ret;
9ae3f9
+    return dict;
9ae3f9
 }
9ae3f9
 
9ae3f9
-int
9ae3f9
-afr_selfheal_locked_data_inspect(call_frame_t *frame, xlator_t *this, fd_t *fd,
9ae3f9
-                                 gf_boolean_t *dsh, unsigned char *pflag)
9ae3f9
+static gf_boolean_t
9ae3f9
+afr_is_dirty_count_non_unary_for_txn(xlator_t *this, struct afr_reply *replies,
9ae3f9
+                                     afr_transaction_type type)
9ae3f9
 {
9ae3f9
-    int ret = -1;
9ae3f9
-    unsigned char *data_lock = NULL;
9ae3f9
-    unsigned char *sources = NULL;
9ae3f9
-    unsigned char *sinks = NULL;
9ae3f9
-    unsigned char *healed_sinks = NULL;
9ae3f9
-    unsigned char *undid_pending = NULL;
9ae3f9
-    afr_private_t *priv = NULL;
9ae3f9
-    struct afr_reply *locked_replies = NULL;
9ae3f9
-    inode_t *inode = fd->inode;
9ae3f9
+    afr_private_t *priv = this->private;
9ae3f9
+    int *dirty = alloca0(priv->child_count * sizeof(int));
9ae3f9
+    int i = 0;
9ae3f9
 
9ae3f9
-    priv = this->private;
9ae3f9
-    data_lock = alloca0(priv->child_count);
9ae3f9
-    sources = alloca0(priv->child_count);
9ae3f9
-    sinks = alloca0(priv->child_count);
9ae3f9
-    healed_sinks = alloca0(priv->child_count);
9ae3f9
-    undid_pending = alloca0(priv->child_count);
9ae3f9
+    afr_selfheal_extract_xattr(this, replies, type, dirty, NULL);
9ae3f9
+    for (i = 0; i < priv->child_count; i++) {
9ae3f9
+        if (dirty[i] > 1)
9ae3f9
+            return _gf_true;
9ae3f9
+    }
9ae3f9
 
9ae3f9
-    locked_replies = alloca0(sizeof(*locked_replies) * priv->child_count);
9ae3f9
+    return _gf_false;
9ae3f9
+}
9ae3f9
 
9ae3f9
-    ret = afr_selfheal_inodelk(frame, this, inode, this->name, 0, 0, data_lock);
9ae3f9
-    {
9ae3f9
-        if (ret == 0) {
9ae3f9
-            ret = -afr_final_errno(frame->local, priv);
9ae3f9
-            if (ret == 0)
9ae3f9
-                ret = -ENOTCONN; /* all invalid responses */
9ae3f9
-            goto out;
9ae3f9
-        }
9ae3f9
-        ret = __afr_selfheal_data_prepare(frame, this, inode, data_lock,
9ae3f9
-                                          sources, sinks, healed_sinks,
9ae3f9
-                                          undid_pending, locked_replies, pflag);
9ae3f9
-        *dsh = afr_decide_heal_info(priv, sources, ret);
9ae3f9
+static gf_boolean_t
9ae3f9
+afr_is_dirty_count_non_unary(xlator_t *this, struct afr_reply *replies,
9ae3f9
+                             ia_type_t ia_type)
9ae3f9
+{
9ae3f9
+    gf_boolean_t data_chk = _gf_false;
9ae3f9
+    gf_boolean_t mdata_chk = _gf_false;
9ae3f9
+    gf_boolean_t entry_chk = _gf_false;
9ae3f9
+
9ae3f9
+    switch (ia_type) {
9ae3f9
+        case IA_IFDIR:
9ae3f9
+            mdata_chk = _gf_true;
9ae3f9
+            entry_chk = _gf_true;
9ae3f9
+            break;
9ae3f9
+        case IA_IFREG:
9ae3f9
+            mdata_chk = _gf_true;
9ae3f9
+            data_chk = _gf_true;
9ae3f9
+            break;
9ae3f9
+        default:
9ae3f9
+            /*IA_IFBLK, IA_IFCHR, IA_IFLNK, IA_IFIFO, IA_IFSOCK*/
9ae3f9
+            mdata_chk = _gf_true;
9ae3f9
+            break;
9ae3f9
     }
9ae3f9
-    afr_selfheal_uninodelk(frame, this, inode, this->name, 0, 0, data_lock);
9ae3f9
-out:
9ae3f9
-    if (locked_replies)
9ae3f9
-        afr_replies_wipe(locked_replies, priv->child_count);
9ae3f9
-    return ret;
9ae3f9
+
9ae3f9
+    if (data_chk && afr_is_dirty_count_non_unary_for_txn(
9ae3f9
+                        this, replies, AFR_DATA_TRANSACTION)) {
9ae3f9
+        return _gf_true;
9ae3f9
+    } else if (mdata_chk && afr_is_dirty_count_non_unary_for_txn(
9ae3f9
+                                this, replies, AFR_METADATA_TRANSACTION)) {
9ae3f9
+        return _gf_true;
9ae3f9
+    } else if (entry_chk && afr_is_dirty_count_non_unary_for_txn(
9ae3f9
+                                this, replies, AFR_ENTRY_TRANSACTION)) {
9ae3f9
+        return _gf_true;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    return _gf_false;
9ae3f9
 }
9ae3f9
 
9ae3f9
-int
9ae3f9
-afr_selfheal_locked_entry_inspect(call_frame_t *frame, xlator_t *this,
9ae3f9
-                                  inode_t *inode, gf_boolean_t *esh,
9ae3f9
-                                  unsigned char *pflag)
9ae3f9
+static int
9ae3f9
+afr_update_heal_status(xlator_t *this, struct afr_reply *replies,
9ae3f9
+                       char *index_vgfid, ia_type_t ia_type, gf_boolean_t *esh,
9ae3f9
+                       gf_boolean_t *dsh, gf_boolean_t *msh)
9ae3f9
 {
9ae3f9
     int ret = -1;
9ae3f9
-    int source = -1;
9ae3f9
+    GF_UNUSED int ret1 = 0;
9ae3f9
+    int i = 0;
9ae3f9
+    int io_domain_lk_count = 0;
9ae3f9
+    int shd_domain_lk_count = 0;
9ae3f9
     afr_private_t *priv = NULL;
9ae3f9
-    unsigned char *locked_on = NULL;
9ae3f9
-    unsigned char *data_lock = NULL;
9ae3f9
-    unsigned char *sources = NULL;
9ae3f9
-    unsigned char *sinks = NULL;
9ae3f9
-    unsigned char *healed_sinks = NULL;
9ae3f9
-    struct afr_reply *locked_replies = NULL;
9ae3f9
-    gf_boolean_t granular_locks = _gf_false;
9ae3f9
+    char *key1 = NULL;
9ae3f9
+    char *key2 = NULL;
9ae3f9
 
9ae3f9
     priv = this->private;
9ae3f9
-    granular_locks = priv->granular_locks; /*Assign to local variable so that
9ae3f9
-                                             reconfigure doesn't change this
9ae3f9
-                                             value between locking and unlocking
9ae3f9
-                                             below*/
9ae3f9
-    locked_on = alloca0(priv->child_count);
9ae3f9
-    data_lock = alloca0(priv->child_count);
9ae3f9
-    sources = alloca0(priv->child_count);
9ae3f9
-    sinks = alloca0(priv->child_count);
9ae3f9
-    healed_sinks = alloca0(priv->child_count);
9ae3f9
-
9ae3f9
-    locked_replies = alloca0(sizeof(*locked_replies) * priv->child_count);
9ae3f9
+    key1 = alloca0(strlen(GLUSTERFS_INODELK_DOM_PREFIX) + 2 +
9ae3f9
+                   strlen(this->name));
9ae3f9
+    key2 = alloca0(strlen(GLUSTERFS_INODELK_DOM_PREFIX) + 2 +
9ae3f9
+                   strlen(priv->sh_domain));
9ae3f9
+    sprintf(key1, "%s:%s", GLUSTERFS_INODELK_DOM_PREFIX, this->name);
9ae3f9
+    sprintf(key2, "%s:%s", GLUSTERFS_INODELK_DOM_PREFIX, priv->sh_domain);
9ae3f9
 
9ae3f9
-    if (!granular_locks) {
9ae3f9
-        ret = afr_selfheal_tryentrylk(frame, this, inode, priv->sh_domain, NULL,
9ae3f9
-                                      locked_on);
9ae3f9
-    }
9ae3f9
-    {
9ae3f9
-        if (!granular_locks && ret == 0) {
9ae3f9
-            ret = -afr_final_errno(frame->local, priv);
9ae3f9
-            if (ret == 0)
9ae3f9
-                ret = -ENOTCONN; /* all invalid responses */
9ae3f9
-            goto out;
9ae3f9
+    for (i = 0; i < priv->child_count; i++) {
9ae3f9
+        if ((replies[i].valid != 1) || (replies[i].op_ret != 0))
9ae3f9
+            continue;
9ae3f9
+        if (!io_domain_lk_count) {
9ae3f9
+            ret1 = dict_get_int32(replies[i].xdata, key1, &io_domain_lk_count);
9ae3f9
         }
9ae3f9
+        if (!shd_domain_lk_count) {
9ae3f9
+            ret1 = dict_get_int32(replies[i].xdata, key2, &shd_domain_lk_count);
9ae3f9
+        }
9ae3f9
+    }
9ae3f9
 
9ae3f9
-        ret = afr_selfheal_entrylk(frame, this, inode, this->name, NULL,
9ae3f9
-                                   data_lock);
9ae3f9
-        {
9ae3f9
-            if (ret == 0) {
9ae3f9
-                ret = -afr_final_errno(frame->local, priv);
9ae3f9
-                if (ret == 0)
9ae3f9
-                    ret = -ENOTCONN;
9ae3f9
-                /* all invalid responses */
9ae3f9
-                goto unlock;
9ae3f9
-            }
9ae3f9
-            ret = __afr_selfheal_entry_prepare(frame, this, inode, data_lock,
9ae3f9
-                                               sources, sinks, healed_sinks,
9ae3f9
-                                               locked_replies, &source, pflag);
9ae3f9
-            if ((ret == 0) && (*pflag & PFLAG_SBRAIN))
9ae3f9
-                ret = -EIO;
9ae3f9
-            *esh = afr_decide_heal_info(priv, sources, ret);
9ae3f9
+    if (!strcmp(index_vgfid, GF_XATTROP_INDEX_GFID)) {
9ae3f9
+        if (shd_domain_lk_count) {
9ae3f9
+            ret = -EAGAIN; /*For 'possibly-healing'. */
9ae3f9
+        } else {
9ae3f9
+            ret = 0; /*needs heal. Just set a non -ve value so that it is
9ae3f9
+                       assumed as the source index.*/
9ae3f9
+        }
9ae3f9
+    } else if (!strcmp(index_vgfid, GF_XATTROP_DIRTY_GFID)) {
9ae3f9
+        if ((afr_is_dirty_count_non_unary(this, replies, ia_type)) ||
9ae3f9
+            (!io_domain_lk_count)) {
9ae3f9
+            /* Needs heal. */
9ae3f9
+            ret = 0;
9ae3f9
+        } else {
9ae3f9
+            /* No heal needed. */
9ae3f9
+            *dsh = *esh = *msh = 0;
9ae3f9
         }
9ae3f9
-        afr_selfheal_unentrylk(frame, this, inode, this->name, NULL, data_lock,
9ae3f9
-                               NULL);
9ae3f9
     }
9ae3f9
-unlock:
9ae3f9
-    if (!granular_locks)
9ae3f9
-        afr_selfheal_unentrylk(frame, this, inode, priv->sh_domain, NULL,
9ae3f9
-                               locked_on, NULL);
9ae3f9
-out:
9ae3f9
-    if (locked_replies)
9ae3f9
-        afr_replies_wipe(locked_replies, priv->child_count);
9ae3f9
     return ret;
9ae3f9
 }
9ae3f9
 
9ae3f9
+/*return EIO, EAGAIN or pending*/
9ae3f9
 int
9ae3f9
-afr_selfheal_locked_inspect(call_frame_t *frame, xlator_t *this, uuid_t gfid,
9ae3f9
-                            inode_t **inode, gf_boolean_t *entry_selfheal,
9ae3f9
-                            gf_boolean_t *data_selfheal,
9ae3f9
-                            gf_boolean_t *metadata_selfheal,
9ae3f9
-                            unsigned char *pending)
9ae3f9
-
9ae3f9
+afr_lockless_inspect(call_frame_t *frame, xlator_t *this, uuid_t gfid,
9ae3f9
+                     inode_t **inode, char *index_vgfid,
9ae3f9
+                     gf_boolean_t *entry_selfheal, gf_boolean_t *data_selfheal,
9ae3f9
+                     gf_boolean_t *metadata_selfheal, unsigned char *pending)
9ae3f9
 {
9ae3f9
     int ret = -1;
9ae3f9
-    fd_t *fd = NULL;
9ae3f9
+    int i = 0;
9ae3f9
+    afr_private_t *priv = NULL;
9ae3f9
+    struct afr_reply *replies = NULL;
9ae3f9
     gf_boolean_t dsh = _gf_false;
9ae3f9
     gf_boolean_t msh = _gf_false;
9ae3f9
     gf_boolean_t esh = _gf_false;
9ae3f9
+    unsigned char *sources = NULL;
9ae3f9
+    unsigned char *sinks = NULL;
9ae3f9
+    unsigned char *valid_on = NULL;
9ae3f9
+    uint64_t *witness = NULL;
9ae3f9
+
9ae3f9
+    priv = this->private;
9ae3f9
+    replies = alloca0(sizeof(*replies) * priv->child_count);
9ae3f9
+    sources = alloca0(sizeof(*sources) * priv->child_count);
9ae3f9
+    sinks = alloca0(sizeof(*sinks) * priv->child_count);
9ae3f9
+    witness = alloca0(sizeof(*witness) * priv->child_count);
9ae3f9
+    valid_on = alloca0(sizeof(*valid_on) * priv->child_count);
9ae3f9
 
9ae3f9
     ret = afr_selfheal_unlocked_inspect(frame, this, gfid, inode, &dsh, &msh,
9ae3f9
-                                        &esh;;
9ae3f9
+                                        &esh, replies);
9ae3f9
     if (ret)
9ae3f9
         goto out;
9ae3f9
-
9ae3f9
-    /* For every heal type hold locks and check if it indeed needs heal */
9ae3f9
-
9ae3f9
-    /* Heal-info does an open() on the file being examined so that the
9ae3f9
-     * current eager-lock holding client, if present, at some point sees
9ae3f9
-     * open-fd count being > 1 and releases the eager-lock so that heal-info
9ae3f9
-     * doesn't remain blocked forever until IO completes.
9ae3f9
-     */
9ae3f9
-    if ((*inode)->ia_type == IA_IFREG) {
9ae3f9
-        ret = afr_selfheal_data_open(this, *inode, &fd;;
9ae3f9
-        if (ret < 0) {
9ae3f9
-            gf_msg_debug(this->name, -ret, "%s: Failed to open",
9ae3f9
-                         uuid_utoa((*inode)->gfid));
9ae3f9
-            goto out;
9ae3f9
+    for (i = 0; i < priv->child_count; i++) {
9ae3f9
+        if (replies[i].valid && replies[i].op_ret == 0) {
9ae3f9
+            valid_on[i] = 1;
9ae3f9
         }
9ae3f9
     }
9ae3f9
-
9ae3f9
     if (msh) {
9ae3f9
-        ret = afr_selfheal_locked_metadata_inspect(frame, this, *inode, &msh,
9ae3f9
-                                                   pending);
9ae3f9
-        if (ret == -EIO)
9ae3f9
+        ret = afr_selfheal_find_direction(frame, this, replies,
9ae3f9
+                                          AFR_METADATA_TRANSACTION, valid_on,
9ae3f9
+                                          sources, sinks, witness, pending);
9ae3f9
+        if (*pending & PFLAG_SBRAIN)
9ae3f9
+            ret = -EIO;
9ae3f9
+        if (ret)
9ae3f9
             goto out;
9ae3f9
     }
9ae3f9
-
9ae3f9
     if (dsh) {
9ae3f9
-        ret = afr_selfheal_locked_data_inspect(frame, this, fd, &dsh, pending);
9ae3f9
-        if (ret == -EIO || (ret == -EAGAIN))
9ae3f9
+        ret = afr_selfheal_find_direction(frame, this, replies,
9ae3f9
+                                          AFR_DATA_TRANSACTION, valid_on,
9ae3f9
+                                          sources, sinks, witness, pending);
9ae3f9
+        if (*pending & PFLAG_SBRAIN)
9ae3f9
+            ret = -EIO;
9ae3f9
+        if (ret)
9ae3f9
             goto out;
9ae3f9
     }
9ae3f9
-
9ae3f9
     if (esh) {
9ae3f9
-        ret = afr_selfheal_locked_entry_inspect(frame, this, *inode, &esh,
9ae3f9
-                                                pending);
9ae3f9
+        ret = afr_selfheal_find_direction(frame, this, replies,
9ae3f9
+                                          AFR_ENTRY_TRANSACTION, valid_on,
9ae3f9
+                                          sources, sinks, witness, pending);
9ae3f9
+        if (*pending & PFLAG_SBRAIN)
9ae3f9
+            ret = -EIO;
9ae3f9
+        if (ret)
9ae3f9
+            goto out;
9ae3f9
     }
9ae3f9
 
9ae3f9
+    ret = afr_update_heal_status(this, replies, index_vgfid, (*inode)->ia_type,
9ae3f9
+                                 &esh, &dsh, &msh;;
9ae3f9
 out:
9ae3f9
     *data_selfheal = dsh;
9ae3f9
     *entry_selfheal = esh;
9ae3f9
     *metadata_selfheal = msh;
9ae3f9
-    if (fd)
9ae3f9
-        fd_unref(fd);
9ae3f9
+    if (replies)
9ae3f9
+        afr_replies_wipe(replies, priv->child_count);
9ae3f9
     return ret;
9ae3f9
 }
9ae3f9
 
9ae3f9
-static dict_t *
9ae3f9
-afr_set_heal_info(char *status)
9ae3f9
-{
9ae3f9
-    dict_t *dict = NULL;
9ae3f9
-    int ret = -1;
9ae3f9
-
9ae3f9
-    dict = dict_new();
9ae3f9
-    if (!dict) {
9ae3f9
-        ret = -ENOMEM;
9ae3f9
-        goto out;
9ae3f9
-    }
9ae3f9
-
9ae3f9
-    ret = dict_set_dynstr_sizen(dict, "heal-info", status);
9ae3f9
-    if (ret)
9ae3f9
-        gf_msg("", GF_LOG_WARNING, -ret, AFR_MSG_DICT_SET_FAILED,
9ae3f9
-               "Failed to set heal-info key to "
9ae3f9
-               "%s",
9ae3f9
-               status);
9ae3f9
-out:
9ae3f9
-    /* Any error other than EINVAL, dict_set_dynstr frees status */
9ae3f9
-    if (ret == -ENOMEM || ret == -EINVAL) {
9ae3f9
-        GF_FREE(status);
9ae3f9
-    }
9ae3f9
-
9ae3f9
-    if (ret && dict) {
9ae3f9
-        dict_unref(dict);
9ae3f9
-        dict = NULL;
9ae3f9
-    }
9ae3f9
-    return dict;
9ae3f9
-}
9ae3f9
-
9ae3f9
 int
9ae3f9
 afr_get_heal_info(call_frame_t *frame, xlator_t *this, loc_t *loc)
9ae3f9
 {
9ae3f9
@@ -6174,10 +6133,18 @@ afr_get_heal_info(call_frame_t *frame, xlator_t *this, loc_t *loc)
9ae3f9
     inode_t *inode = NULL;
9ae3f9
     char *substr = NULL;
9ae3f9
     char *status = NULL;
9ae3f9
+    afr_local_t *local = NULL;
9ae3f9
+    char *index_vgfid = NULL;
9ae3f9
+
9ae3f9
+    local = frame->local;
9ae3f9
+    if (dict_get_str(local->xdata_req, "index-vgfid", &index_vgfid)) {
9ae3f9
+        ret = -1;
9ae3f9
+        goto out;
9ae3f9
+    }
9ae3f9
 
9ae3f9
-    ret = afr_selfheal_locked_inspect(frame, this, loc->gfid, &inode,
9ae3f9
-                                      &entry_selfheal, &data_selfheal,
9ae3f9
-                                      &metadata_selfheal, &pending);
9ae3f9
+    ret = afr_lockless_inspect(frame, this, loc->gfid, &inode, index_vgfid,
9ae3f9
+                               &entry_selfheal, &data_selfheal,
9ae3f9
+                               &metadata_selfheal, &pending);
9ae3f9
 
9ae3f9
     if (ret == -ENOMEM) {
9ae3f9
         ret = -1;
9ae3f9
diff --git a/xlators/cluster/afr/src/afr-self-heal-common.c b/xlators/cluster/afr/src/afr-self-heal-common.c
9ae3f9
index d942ccf..1608f75 100644
9ae3f9
--- a/xlators/cluster/afr/src/afr-self-heal-common.c
9ae3f9
+++ b/xlators/cluster/afr/src/afr-self-heal-common.c
9ae3f9
@@ -1827,6 +1827,37 @@ afr_selfheal_unlocked_lookup_on(call_frame_t *frame, inode_t *parent,
9ae3f9
     return inode;
9ae3f9
 }
9ae3f9
 
9ae3f9
+static int
9ae3f9
+afr_set_multi_dom_lock_count_request(xlator_t *this, dict_t *dict)
9ae3f9
+{
9ae3f9
+    int ret = 0;
9ae3f9
+    afr_private_t *priv = NULL;
9ae3f9
+    char *key1 = NULL;
9ae3f9
+    char *key2 = NULL;
9ae3f9
+
9ae3f9
+    priv = this->private;
9ae3f9
+    key1 = alloca0(strlen(GLUSTERFS_INODELK_DOM_PREFIX) + 2 +
9ae3f9
+                   strlen(this->name));
9ae3f9
+    key2 = alloca0(strlen(GLUSTERFS_INODELK_DOM_PREFIX) + 2 +
9ae3f9
+                   strlen(priv->sh_domain));
9ae3f9
+
9ae3f9
+    ret = dict_set_uint32(dict, GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS, 1);
9ae3f9
+    if (ret)
9ae3f9
+        return ret;
9ae3f9
+
9ae3f9
+    sprintf(key1, "%s:%s", GLUSTERFS_INODELK_DOM_PREFIX, this->name);
9ae3f9
+    ret = dict_set_uint32(dict, key1, 1);
9ae3f9
+    if (ret)
9ae3f9
+        return ret;
9ae3f9
+
9ae3f9
+    sprintf(key2, "%s:%s", GLUSTERFS_INODELK_DOM_PREFIX, priv->sh_domain);
9ae3f9
+    ret = dict_set_uint32(dict, key2, 1);
9ae3f9
+    if (ret)
9ae3f9
+        return ret;
9ae3f9
+
9ae3f9
+    return 0;
9ae3f9
+}
9ae3f9
+
9ae3f9
 int
9ae3f9
 afr_selfheal_unlocked_discover_on(call_frame_t *frame, inode_t *inode,
9ae3f9
                                   uuid_t gfid, struct afr_reply *replies,
9ae3f9
@@ -1851,6 +1882,11 @@ afr_selfheal_unlocked_discover_on(call_frame_t *frame, inode_t *inode,
9ae3f9
         return -ENOMEM;
9ae3f9
     }
9ae3f9
 
9ae3f9
+    if (afr_set_multi_dom_lock_count_request(frame->this, xattr_req)) {
9ae3f9
+        dict_unref(xattr_req);
9ae3f9
+        return -1;
9ae3f9
+    }
9ae3f9
+
9ae3f9
     loc.inode = inode_ref(inode);
9ae3f9
     gf_uuid_copy(loc.gfid, gfid);
9ae3f9
 
9ae3f9
@@ -2241,7 +2277,8 @@ int
9ae3f9
 afr_selfheal_unlocked_inspect(call_frame_t *frame, xlator_t *this, uuid_t gfid,
9ae3f9
                               inode_t **link_inode, gf_boolean_t *data_selfheal,
9ae3f9
                               gf_boolean_t *metadata_selfheal,
9ae3f9
-                              gf_boolean_t *entry_selfheal)
9ae3f9
+                              gf_boolean_t *entry_selfheal,
9ae3f9
+                              struct afr_reply *replies_dst)
9ae3f9
 {
9ae3f9
     afr_private_t *priv = NULL;
9ae3f9
     inode_t *inode = NULL;
9ae3f9
@@ -2377,6 +2414,8 @@ afr_selfheal_unlocked_inspect(call_frame_t *frame, xlator_t *this, uuid_t gfid,
9ae3f9
 
9ae3f9
     ret = 0;
9ae3f9
 out:
9ae3f9
+    if (replies && replies_dst)
9ae3f9
+        afr_replies_copy(replies_dst, replies, priv->child_count);
9ae3f9
     if (inode)
9ae3f9
         inode_unref(inode);
9ae3f9
     if (replies)
9ae3f9
@@ -2493,7 +2532,7 @@ afr_selfheal_do(call_frame_t *frame, xlator_t *this, uuid_t gfid)
9ae3f9
 
9ae3f9
     ret = afr_selfheal_unlocked_inspect(frame, this, gfid, &inode,
9ae3f9
                                         &data_selfheal, &metadata_selfheal,
9ae3f9
-                                        &entry_selfheal);
9ae3f9
+                                        &entry_selfheal, NULL);
9ae3f9
     if (ret)
9ae3f9
         goto out;
9ae3f9
 
9ae3f9
diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h
9ae3f9
index f7ecf5d..b39af02 100644
9ae3f9
--- a/xlators/cluster/afr/src/afr-self-heal.h
9ae3f9
+++ b/xlators/cluster/afr/src/afr-self-heal.h
9ae3f9
@@ -327,7 +327,8 @@ int
9ae3f9
 afr_selfheal_unlocked_inspect(call_frame_t *frame, xlator_t *this, uuid_t gfid,
9ae3f9
                               inode_t **link_inode, gf_boolean_t *data_selfheal,
9ae3f9
                               gf_boolean_t *metadata_selfheal,
9ae3f9
-                              gf_boolean_t *entry_selfheal);
9ae3f9
+                              gf_boolean_t *entry_selfheal,
9ae3f9
+                              struct afr_reply *replies);
9ae3f9
 
9ae3f9
 int
9ae3f9
 afr_selfheal_do(call_frame_t *frame, xlator_t *this, uuid_t gfid);
9ae3f9
diff --git a/xlators/features/locks/src/common.h b/xlators/features/locks/src/common.h
9ae3f9
index 3a74967..ea86b96 100644
9ae3f9
--- a/xlators/features/locks/src/common.h
9ae3f9
+++ b/xlators/features/locks/src/common.h
9ae3f9
@@ -45,6 +45,10 @@
9ae3f9
                 fd_unref(__local->fd);                                         \
9ae3f9
             if (__local->inode)                                                \
9ae3f9
                 inode_unref(__local->inode);                                   \
9ae3f9
+            if (__local->xdata) {                                              \
9ae3f9
+                dict_unref(__local->xdata);                                    \
9ae3f9
+                __local->xdata = NULL;                                         \
9ae3f9
+            }                                                                  \
9ae3f9
             mem_put(__local);                                                  \
9ae3f9
         }                                                                      \
9ae3f9
     } while (0)
9ae3f9
diff --git a/xlators/features/locks/src/locks.h b/xlators/features/locks/src/locks.h
9ae3f9
index b817960..aa267de 100644
9ae3f9
--- a/xlators/features/locks/src/locks.h
9ae3f9
+++ b/xlators/features/locks/src/locks.h
9ae3f9
@@ -239,6 +239,7 @@ typedef struct {
9ae3f9
     gf_boolean_t inodelk_count_req;
9ae3f9
     gf_boolean_t posixlk_count_req;
9ae3f9
     gf_boolean_t parent_entrylk_req;
9ae3f9
+    gf_boolean_t multiple_dom_lk_requests;
9ae3f9
     int update_mlock_enforced_flag;
9ae3f9
 } pl_local_t;
9ae3f9
 
9ae3f9
@@ -260,6 +261,13 @@ typedef struct _locks_ctx {
9ae3f9
     struct list_head metalk_list;
9ae3f9
 } pl_ctx_t;
9ae3f9
 
9ae3f9
+typedef struct _multi_dom_lk_data {
9ae3f9
+    xlator_t *this;
9ae3f9
+    inode_t *inode;
9ae3f9
+    dict_t *xdata_rsp;
9ae3f9
+    gf_boolean_t keep_max;
9ae3f9
+} multi_dom_lk_data;
9ae3f9
+
9ae3f9
 typedef enum { DECREMENT, INCREMENT } pl_count_op_t;
9ae3f9
 
9ae3f9
 pl_ctx_t *
9ae3f9
diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c
9ae3f9
index 4592240..9a14c64 100644
9ae3f9
--- a/xlators/features/locks/src/posix.c
9ae3f9
+++ b/xlators/features/locks/src/posix.c
9ae3f9
@@ -150,13 +150,20 @@ fetch_pathinfo(xlator_t *, inode_t *, int32_t *, char **);
9ae3f9
 gf_boolean_t
9ae3f9
 pl_has_xdata_requests(dict_t *xdata)
9ae3f9
 {
9ae3f9
-    static char *reqs[] = {GLUSTERFS_ENTRYLK_COUNT,     GLUSTERFS_INODELK_COUNT,
9ae3f9
-                           GLUSTERFS_INODELK_DOM_COUNT, GLUSTERFS_POSIXLK_COUNT,
9ae3f9
-                           GLUSTERFS_PARENT_ENTRYLK,    NULL};
9ae3f9
-    static int reqs_size[] = {
9ae3f9
-        SLEN(GLUSTERFS_ENTRYLK_COUNT),     SLEN(GLUSTERFS_INODELK_COUNT),
9ae3f9
-        SLEN(GLUSTERFS_INODELK_DOM_COUNT), SLEN(GLUSTERFS_POSIXLK_COUNT),
9ae3f9
-        SLEN(GLUSTERFS_PARENT_ENTRYLK),    0};
9ae3f9
+    static char *reqs[] = {GLUSTERFS_ENTRYLK_COUNT,
9ae3f9
+                           GLUSTERFS_INODELK_COUNT,
9ae3f9
+                           GLUSTERFS_INODELK_DOM_COUNT,
9ae3f9
+                           GLUSTERFS_POSIXLK_COUNT,
9ae3f9
+                           GLUSTERFS_PARENT_ENTRYLK,
9ae3f9
+                           GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS,
9ae3f9
+                           NULL};
9ae3f9
+    static int reqs_size[] = {SLEN(GLUSTERFS_ENTRYLK_COUNT),
9ae3f9
+                              SLEN(GLUSTERFS_INODELK_COUNT),
9ae3f9
+                              SLEN(GLUSTERFS_INODELK_DOM_COUNT),
9ae3f9
+                              SLEN(GLUSTERFS_POSIXLK_COUNT),
9ae3f9
+                              SLEN(GLUSTERFS_PARENT_ENTRYLK),
9ae3f9
+                              SLEN(GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS),
9ae3f9
+                              0};
9ae3f9
     int i = 0;
9ae3f9
 
9ae3f9
     if (!xdata)
9ae3f9
@@ -169,12 +176,22 @@ pl_has_xdata_requests(dict_t *xdata)
9ae3f9
     return _gf_false;
9ae3f9
 }
9ae3f9
 
9ae3f9
+static int
9ae3f9
+dict_delete_domain_key(dict_t *dict, char *key, data_t *value, void *data)
9ae3f9
+{
9ae3f9
+    dict_del(dict, key);
9ae3f9
+    return 0;
9ae3f9
+}
9ae3f9
+
9ae3f9
 void
9ae3f9
 pl_get_xdata_requests(pl_local_t *local, dict_t *xdata)
9ae3f9
 {
9ae3f9
     if (!local || !xdata)
9ae3f9
         return;
9ae3f9
 
9ae3f9
+    GF_ASSERT(local->xdata == NULL);
9ae3f9
+    local->xdata = dict_copy_with_ref(xdata, NULL);
9ae3f9
+
9ae3f9
     if (dict_get_sizen(xdata, GLUSTERFS_ENTRYLK_COUNT)) {
9ae3f9
         local->entrylk_count_req = 1;
9ae3f9
         dict_del_sizen(xdata, GLUSTERFS_ENTRYLK_COUNT);
9ae3f9
@@ -183,6 +200,12 @@ pl_get_xdata_requests(pl_local_t *local, dict_t *xdata)
9ae3f9
         local->inodelk_count_req = 1;
9ae3f9
         dict_del_sizen(xdata, GLUSTERFS_INODELK_COUNT);
9ae3f9
     }
9ae3f9
+    if (dict_get_sizen(xdata, GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS)) {
9ae3f9
+        local->multiple_dom_lk_requests = 1;
9ae3f9
+        dict_del_sizen(xdata, GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS);
9ae3f9
+        dict_foreach_fnmatch(xdata, GLUSTERFS_INODELK_DOM_PREFIX "*",
9ae3f9
+                             dict_delete_domain_key, NULL);
9ae3f9
+    }
9ae3f9
 
9ae3f9
     local->inodelk_dom_count_req = dict_get_sizen(xdata,
9ae3f9
                                                   GLUSTERFS_INODELK_DOM_COUNT);
9ae3f9
@@ -210,7 +233,7 @@ pl_needs_xdata_response(pl_local_t *local)
9ae3f9
 
9ae3f9
     if (local->parent_entrylk_req || local->entrylk_count_req ||
9ae3f9
         local->inodelk_dom_count_req || local->inodelk_count_req ||
9ae3f9
-        local->posixlk_count_req)
9ae3f9
+        local->posixlk_count_req || local->multiple_dom_lk_requests)
9ae3f9
         return _gf_true;
9ae3f9
 
9ae3f9
     return _gf_false;
9ae3f9
@@ -411,6 +434,75 @@ pl_posixlk_xattr_fill(xlator_t *this, inode_t *inode, dict_t *dict,
9ae3f9
 }
9ae3f9
 
9ae3f9
 void
9ae3f9
+pl_inodelk_xattr_fill_each(xlator_t *this, inode_t *inode, dict_t *dict,
9ae3f9
+                           char *domname, gf_boolean_t keep_max, char *key)
9ae3f9
+{
9ae3f9
+    int32_t count = 0;
9ae3f9
+    int32_t maxcount = -1;
9ae3f9
+    int ret = -1;
9ae3f9
+
9ae3f9
+    if (keep_max) {
9ae3f9
+        ret = dict_get_int32(dict, key, &maxcount);
9ae3f9
+        if (ret < 0)
9ae3f9
+            gf_msg_debug(this->name, 0, " Failed to fetch the value for key %s",
9ae3f9
+                         GLUSTERFS_INODELK_COUNT);
9ae3f9
+    }
9ae3f9
+    count = get_inodelk_count(this, inode, domname);
9ae3f9
+    if (maxcount >= count)
9ae3f9
+        return;
9ae3f9
+
9ae3f9
+    ret = dict_set_int32(dict, key, count);
9ae3f9
+    if (ret < 0) {
9ae3f9
+        gf_msg_debug(this->name, 0,
9ae3f9
+                     "Failed to set count for "
9ae3f9
+                     "key %s",
9ae3f9
+                     key);
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    return;
9ae3f9
+}
9ae3f9
+
9ae3f9
+static int
9ae3f9
+pl_inodelk_xattr_fill_multiple(dict_t *this, char *key, data_t *value,
9ae3f9
+                               void *data)
9ae3f9
+{
9ae3f9
+    multi_dom_lk_data *d = data;
9ae3f9
+    char *tmp_key = NULL;
9ae3f9
+    char *save_ptr = NULL;
9ae3f9
+
9ae3f9
+    tmp_key = gf_strdup(key);
9ae3f9
+    strtok_r(tmp_key, ":", &save_ptr);
9ae3f9
+    if (!*save_ptr) {
9ae3f9
+        gf_msg(THIS->name, GF_LOG_ERROR, 0, EINVAL,
9ae3f9
+               "Could not tokenize domain string from key %s", key);
9ae3f9
+        return -1;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    pl_inodelk_xattr_fill_each(d->this, d->inode, d->xdata_rsp, save_ptr,
9ae3f9
+                               d->keep_max, key);
9ae3f9
+    if (tmp_key)
9ae3f9
+        GF_FREE(tmp_key);
9ae3f9
+
9ae3f9
+    return 0;
9ae3f9
+}
9ae3f9
+
9ae3f9
+void
9ae3f9
+pl_fill_multiple_dom_lk_requests(xlator_t *this, pl_local_t *local,
9ae3f9
+                                 inode_t *inode, dict_t *dict,
9ae3f9
+                                 gf_boolean_t keep_max)
9ae3f9
+{
9ae3f9
+    multi_dom_lk_data data;
9ae3f9
+
9ae3f9
+    data.this = this;
9ae3f9
+    data.inode = inode;
9ae3f9
+    data.xdata_rsp = dict;
9ae3f9
+    data.keep_max = keep_max;
9ae3f9
+
9ae3f9
+    dict_foreach_fnmatch(local->xdata, GLUSTERFS_INODELK_DOM_PREFIX "*",
9ae3f9
+                         pl_inodelk_xattr_fill_multiple, &data);
9ae3f9
+}
9ae3f9
+
9ae3f9
+void
9ae3f9
 pl_set_xdata_response(xlator_t *this, pl_local_t *local, inode_t *parent,
9ae3f9
                       inode_t *inode, char *name, dict_t *xdata,
9ae3f9
                       gf_boolean_t max_lock)
9ae3f9
@@ -437,6 +529,9 @@ pl_set_xdata_response(xlator_t *this, pl_local_t *local, inode_t *parent,
9ae3f9
 
9ae3f9
     if (local->posixlk_count_req)
9ae3f9
         pl_posixlk_xattr_fill(this, inode, xdata, max_lock);
9ae3f9
+
9ae3f9
+    if (local->multiple_dom_lk_requests)
9ae3f9
+        pl_fill_multiple_dom_lk_requests(this, local, inode, xdata, max_lock);
9ae3f9
 }
9ae3f9
 
9ae3f9
 /* Checks whether the region where fop is acting upon conflicts
9ae3f9
@@ -773,9 +868,6 @@ pl_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
9ae3f9
 {
9ae3f9
     pl_local_t *local = frame->local;
9ae3f9
 
9ae3f9
-    if (local->xdata)
9ae3f9
-        dict_unref(local->xdata);
9ae3f9
-
9ae3f9
     pl_track_io_fop_count(local, this, DECREMENT);
9ae3f9
 
9ae3f9
     if (local->op == GF_FOP_TRUNCATE)
9ae3f9
@@ -932,9 +1024,6 @@ unwind:
9ae3f9
                "ret: %d, error: %s",
9ae3f9
                op_ret, strerror(op_errno));
9ae3f9
 
9ae3f9
-        if (local->xdata)
9ae3f9
-            dict_unref(local->xdata);
9ae3f9
-
9ae3f9
         switch (local->op) {
9ae3f9
             case GF_FOP_TRUNCATE:
9ae3f9
                 PL_STACK_UNWIND(truncate, xdata, frame, op_ret, op_errno, buf,
9ae3f9
-- 
9ae3f9
1.8.3.1
9ae3f9