d1681e
From 27081fda822921e7f452304bea170d2d13cba257 Mon Sep 17 00:00:00 2001
d1681e
From: Mohit Agrawal <moagrawa@redhat.com>
d1681e
Date: Fri, 12 May 2017 21:12:47 +0530
d1681e
Subject: [PATCH 205/212] cluster/dht : User xattrs are not healed after brick
d1681e
 stop/start
d1681e
d1681e
Problem: In a distributed volume custom extended attribute value for a directory
d1681e
         does not display correct value after stop/start or added newly brick.
d1681e
         If any extended(acl) attribute value is set for a directory after stop/added
d1681e
         the brick the attribute(user|acl|quota) value is not updated on brick
d1681e
         after start the brick.
d1681e
d1681e
Solution: First store hashed subvol or subvol(has internal xattr) on inode ctx and
d1681e
          consider it as a MDS subvol.At the time of update custom xattr
d1681e
          (user,quota,acl, selinux) on directory first check the mds from
d1681e
          inode ctx, if mds is not present on inode ctx then throw EINVAL error
d1681e
          to application otherwise set xattr on MDS subvol with internal xattr
d1681e
          value of -1 and then try to update the attribute on other non MDS
d1681e
          volumes also.If mds subvol is down in that case throw an
d1681e
          error "Transport endpoint is not connected". In dht_dir_lookup_cbk|
d1681e
          dht_revalidate_cbk|dht_discover_complete call dht_call_dir_xattr_heal
d1681e
          to heal custom extended attribute.
d1681e
          In case of gnfs server if hashed subvol has not found based on
d1681e
          loc then wind a call on all subvol to update xattr.
d1681e
d1681e
Fix:    1) Save MDS subvol on inode ctx
d1681e
        2) Check if mds subvol is present on inode ctx
d1681e
        3) If mds subvol is down then call unwind with error ENOTCONN and if it is up
d1681e
           then set new xattr "GF_DHT_XATTR_MDS" to -1 and wind a call on other
d1681e
           subvol.
d1681e
        4) If setxattr fop is successful on non-mds subvol then increment the value of
d1681e
           internal xattr to +1
d1681e
        5) At the time of directory_lookup check the value of new xattr GF_DHT_XATTR_MDS
d1681e
        6) If value is not 0 in dht_lookup_dir_cbk(other cbk) functions then call heal
d1681e
           function to heal user xattr
d1681e
        7) syncop_setxattr on hashed_subvol to reset the value of xattr to 0
d1681e
           if heal is successful on all subvol.
d1681e
d1681e
Test : To reproduce the issue followed below steps
d1681e
       1) Create a distributed volume and create mount point
d1681e
       2) Create some directory from mount point mkdir tmp{1..5}
d1681e
       3) Kill any one brick from the volume
d1681e
       4) Set extended attribute from mount point on directory
d1681e
          setfattr -n user.foo -v "abc" ./tmp{1..5}
d1681e
          It will throw error " Transport End point is not connected "
d1681e
          for those hashed subvol is down
d1681e
       5) Start volume with force option to start brick process
d1681e
       6) Execute getfattr command on mount point for directory
d1681e
       7) Check extended attribute on brick
d1681e
          getfattr -n user.foo <volume-location>/tmp{1..5}
d1681e
          It shows correct value for directories for those
d1681e
          xattr fop were executed successfully.
d1681e
d1681e
Note: The patch will resolve xattr healing problem only for fuse mount
d1681e
      not for nfs mount.
d1681e
d1681e
> BUG: 1371806
d1681e
> Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
d1681e
> (Cherry pick from commit 9b4de61a136b8e5ba7bf0e48690cdb1292d0dee8)
d1681e
> (Upstream patch link https://review.gluster.org/#/c/15468/)
d1681e
d1681e
BUG: 1550315
d1681e
Change-Id: I4eb137eace24a8cb796712b742f1d177a65343d5
d1681e
Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
d1681e
Reviewed-on: https://code.engineering.redhat.com/gerrit/132383
d1681e
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d1681e
Reviewed-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
d1681e
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
d1681e
---
d1681e
 tests/bugs/bug-1368312.t                  |   30 +-
d1681e
 tests/bugs/bug-1371806.t                  |   80 ++
d1681e
 tests/bugs/bug-1371806_1.t                |   49 +
d1681e
 tests/bugs/bug-1371806_2.t                |   52 ++
d1681e
 tests/bugs/bug-1371806_3.t                |   63 ++
d1681e
 tests/bugs/bug-1371806_acl.t              |   90 ++
d1681e
 tests/bugs/distribute/bug-862967.t        |    7 +-
d1681e
 xlators/cluster/dht/src/dht-common.c      | 1389 ++++++++++++++++++++++++++---
d1681e
 xlators/cluster/dht/src/dht-common.h      |   72 +-
d1681e
 xlators/cluster/dht/src/dht-helper.c      |   65 ++
d1681e
 xlators/cluster/dht/src/dht-inode-write.c |  163 +++-
d1681e
 xlators/cluster/dht/src/dht-messages.h    |   28 +-
d1681e
 xlators/cluster/dht/src/dht-selfheal.c    |  519 ++++++++++-
d1681e
 xlators/cluster/dht/src/dht-shared.c      |    2 +
d1681e
 14 files changed, 2436 insertions(+), 173 deletions(-)
d1681e
 create mode 100644 tests/bugs/bug-1371806.t
d1681e
 create mode 100644 tests/bugs/bug-1371806_1.t
d1681e
 create mode 100644 tests/bugs/bug-1371806_2.t
d1681e
 create mode 100644 tests/bugs/bug-1371806_3.t
d1681e
 create mode 100644 tests/bugs/bug-1371806_acl.t
d1681e
d1681e
diff --git a/tests/bugs/bug-1368312.t b/tests/bugs/bug-1368312.t
d1681e
index 135048f..61e5606 100644
d1681e
--- a/tests/bugs/bug-1368312.t
d1681e
+++ b/tests/bugs/bug-1368312.t
d1681e
@@ -29,46 +29,46 @@ TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0;
d1681e
 TEST mkdir $M0/tmp1
d1681e
 
d1681e
 #Create metadata split-brain
d1681e
-TEST kill_brick $V0 $H0 $B0/${V0}0
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}2
d1681e
 TEST chmod 666 $M0/tmp1
d1681e
 TEST $CLI volume start $V0 force
d1681e
-TEST kill_brick $V0 $H0 $B0/${V0}1
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}3
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
d1681e
 
d1681e
 TEST chmod 757 $M0/tmp1
d1681e
 
d1681e
 TEST $CLI volume start $V0 force
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3
d1681e
 
d1681e
 EXPECT 2 get_pending_heal_count $V0
d1681e
 
d1681e
 
d1681e
-TEST kill_brick $V0 $H0 $B0/${V0}2
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}4
d1681e
 TEST chmod 755 $M0/tmp1
d1681e
 TEST $CLI volume start $V0 force
d1681e
-TEST kill_brick $V0 $H0 $B0/${V0}3
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}5
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4
d1681e
 
d1681e
 TEST chmod 766 $M0/tmp1
d1681e
 
d1681e
 TEST $CLI volume start $V0 force
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 5
d1681e
 
d1681e
 EXPECT 4 get_pending_heal_count $V0
d1681e
 
d1681e
-TEST kill_brick $V0 $H0 $B0/${V0}4
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}0
d1681e
 TEST chmod 765 $M0/tmp1
d1681e
 TEST $CLI volume start $V0 force
d1681e
-TEST kill_brick $V0 $H0 $B0/${V0}5
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}1
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d1681e
 
d1681e
 TEST chmod 756 $M0/tmp1
d1681e
 
d1681e
 TEST $CLI volume start $V0 force
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4
d1681e
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 5
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d1681e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d1681e
 
d1681e
 EXPECT 6 get_pending_heal_count $V0
d1681e
 
d1681e
diff --git a/tests/bugs/bug-1371806.t b/tests/bugs/bug-1371806.t
d1681e
new file mode 100644
d1681e
index 0000000..7dc1613
d1681e
--- /dev/null
d1681e
+++ b/tests/bugs/bug-1371806.t
d1681e
@@ -0,0 +1,80 @@
d1681e
+#!/bin/bash
d1681e
+. $(dirname $0)/../include.rc
d1681e
+. $(dirname $0)/../volume.rc
d1681e
+. $(dirname $0)/../dht.rc
d1681e
+cleanup;
d1681e
+
d1681e
+function get_getfattr {
d1681e
+        local path=$1
d1681e
+        echo `getfattr -n user.foo $path` | cut -f2 -d"=" | sed -e 's/^"//'  -e 's/"$//'
d1681e
+}
d1681e
+
d1681e
+function set_fattr {
d1681e
+        for i in `seq 1 10`
d1681e
+        do
d1681e
+                setfattr -n user.foo -v "newabc" ./tmp${i}
d1681e
+                if [ "$?" = "0" ]
d1681e
+                 then
d1681e
+                    succ=$((succ+1))
d1681e
+                else
d1681e
+                    fail=$((fail+1))
d1681e
+                fi
d1681e
+        done
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+TEST glusterd
d1681e
+TEST pidof glusterd
d1681e
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3,4,5}
d1681e
+TEST $CLI volume start $V0
d1681e
+
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+TEST mkdir tmp{1..10}
d1681e
+
d1681e
+##First set user.foo xattr with value abc on all dirs
d1681e
+
d1681e
+TEST setfattr -n user.foo -v "abc" ./tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr ./tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr $B0/${V0}5/tmp{1..10}
d1681e
+
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}5
d1681e
+EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "5" online_brick_count
d1681e
+
d1681e
+succ=fail=0
d1681e
+## set user.foo xattr with value newabc after kill one brick
d1681e
+set_fattr
d1681e
+TEST $CLI volume start $V0 force
d1681e
+EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "6" online_brick_count
d1681e
+
d1681e
+cd -
d1681e
+TEST umount $M0
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+## At this point dht code will heal xattr on down brick only for those dirs
d1681e
+## hashed subvol was up at the time of update xattr
d1681e
+TEST stat ./tmp{1..10}
d1681e
+
d1681e
+## Count the user.foo xattr value with abc on mount point and compare with fail value
d1681e
+count=`getfattr -n user.foo ./tmp{1..10} | grep "user.foo" | grep -iw "abc" | wc -l`
d1681e
+EXPECT "$fail" echo $count
d1681e
+
d1681e
+## Count the user.foo xattr value with newabc on mount point and compare with succ value
d1681e
+count=`getfattr -n user.foo ./tmp{1..10} | grep "user.foo" | grep -iw "newabc" | wc -l`
d1681e
+EXPECT "$succ" echo $count
d1681e
+
d1681e
+## Count the user.foo xattr value with abc on brick and compare with succ value
d1681e
+count=`getfattr -n user.foo $B0/${V0}5/tmp{1..10} | grep "user.foo" | grep -iw "abc" | wc -l`
d1681e
+EXPECT "$fail" echo $count
d1681e
+
d1681e
+## Count the user.foo xattr value with newabc on brick and compare with succ value
d1681e
+count=`getfattr -n user.foo $B0/${V0}5/tmp{1..10} | grep "user.foo" | grep -iw "newabc" | wc -l`
d1681e
+EXPECT "$succ" echo $count
d1681e
+
d1681e
+
d1681e
+cd -
d1681e
+cleanup
d1681e
+exit
d1681e
diff --git a/tests/bugs/bug-1371806_1.t b/tests/bugs/bug-1371806_1.t
d1681e
new file mode 100644
d1681e
index 0000000..44a57a9
d1681e
--- /dev/null
d1681e
+++ b/tests/bugs/bug-1371806_1.t
d1681e
@@ -0,0 +1,49 @@
d1681e
+#!/bin/bash
d1681e
+. $(dirname $0)/../include.rc
d1681e
+. $(dirname $0)/../volume.rc
d1681e
+. $(dirname $0)/../dht.rc
d1681e
+cleanup;
d1681e
+
d1681e
+function get_getfattr {
d1681e
+        local path=$1
d1681e
+        echo `getfattr -n user.foo $path` | cut -f2 -d"=" | sed -e 's/^"//'  -e 's/"$//'
d1681e
+}
d1681e
+
d1681e
+function remove_mds_xattr {
d1681e
+
d1681e
+       for i in `seq 1 10`
d1681e
+       do
d1681e
+               setfattr -x trusted.glusterfs.dht.mds $1/tmp${i} 2> /dev/null
d1681e
+       done
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+TEST glusterd
d1681e
+TEST pidof glusterd
d1681e
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3}
d1681e
+TEST $CLI volume start $V0
d1681e
+
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+TEST mkdir tmp{1..10}
d1681e
+
d1681e
+##Remove internal mds xattr from all directory
d1681e
+remove_mds_xattr $B0/${V0}0
d1681e
+remove_mds_xattr $B0/${V0}1
d1681e
+remove_mds_xattr $B0/${V0}2
d1681e
+remove_mds_xattr $B0/${V0}3
d1681e
+
d1681e
+cd -
d1681e
+umount $M0
d1681e
+
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0;
d1681e
+cd $M0
d1681e
+
d1681e
+TEST setfattr -n user.foo -v "abc" ./tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr ./tmp{1..10}
d1681e
+
d1681e
+cd -
d1681e
+cleanup
d1681e
+exit
d1681e
diff --git a/tests/bugs/bug-1371806_2.t b/tests/bugs/bug-1371806_2.t
d1681e
new file mode 100644
d1681e
index 0000000..e6aa8e7
d1681e
--- /dev/null
d1681e
+++ b/tests/bugs/bug-1371806_2.t
d1681e
@@ -0,0 +1,52 @@
d1681e
+#!/bin/bash
d1681e
+. $(dirname $0)/../include.rc
d1681e
+. $(dirname $0)/../volume.rc
d1681e
+. $(dirname $0)/../dht.rc
d1681e
+cleanup;
d1681e
+
d1681e
+function get_getfattr {
d1681e
+        local path=$1
d1681e
+        echo `getfattr -n user.foo $path` | cut -f2 -d"=" | sed -e 's/^"//'  -e 's/"$//'
d1681e
+}
d1681e
+
d1681e
+function remove_mds_xattr {
d1681e
+
d1681e
+       for i in `seq 1 10`
d1681e
+       do
d1681e
+               setfattr -x trusted.glusterfs.dht.mds $1/tmp${i} 2> /dev/null
d1681e
+       done
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
+TEST glusterd
d1681e
+TEST pidof glusterd
d1681e
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3}
d1681e
+TEST $CLI volume start $V0
d1681e
+
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 --attribute-timeout=0 $M0;
d1681e
+cd $M0
d1681e
+TEST mkdir tmp{1..10}
d1681e
+
d1681e
+##Remove internal mds xattr from all directory
d1681e
+remove_mds_xattr $B0/${V0}0
d1681e
+remove_mds_xattr $B0/${V0}1
d1681e
+remove_mds_xattr $B0/${V0}2
d1681e
+remove_mds_xattr $B0/${V0}3
d1681e
+
d1681e
+##First set user.foo xattr with value abc on all dirs
d1681e
+
d1681e
+TEST setfattr -n user.foo -v "abc" ./tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr ./tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr $B0/${V0}0/tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr $B0/${V0}1/tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr $B0/${V0}2/tmp{1..10}
d1681e
+EXPECT "abc" get_getfattr $B0/${V0}3/tmp{1..10}
d1681e
+
d1681e
+cd -
d1681e
+TEST umount $M0
d1681e
+
d1681e
+cd -
d1681e
+cleanup
d1681e
+exit
d1681e
diff --git a/tests/bugs/bug-1371806_3.t b/tests/bugs/bug-1371806_3.t
d1681e
new file mode 100644
d1681e
index 0000000..cb13f37
d1681e
--- /dev/null
d1681e
+++ b/tests/bugs/bug-1371806_3.t
d1681e
@@ -0,0 +1,63 @@
d1681e
+#!/bin/bash
d1681e
+. $(dirname $0)/../include.rc
d1681e
+. $(dirname $0)/../volume.rc
d1681e
+. $(dirname $0)/../dht.rc
d1681e
+cleanup;
d1681e
+
d1681e
+function get_getfattr {
d1681e
+        local path=$1
d1681e
+        echo `getfattr -n user.foo $path` | cut -f2 -d"=" | sed -e 's/^"//'  -e 's/"$//'
d1681e
+}
d1681e
+
d1681e
+function set_fattr {
d1681e
+        for i in `seq 1 10`
d1681e
+        do
d1681e
+                setfattr -n user.foo -v "newabc" ./tmp${i}
d1681e
+                if [ "$?" = "0" ]
d1681e
+                 then
d1681e
+                    succ=$((succ+1))
d1681e
+                else
d1681e
+                    fail=$((fail+1))
d1681e
+                fi
d1681e
+        done
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+TEST glusterd
d1681e
+TEST pidof glusterd
d1681e
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3}
d1681e
+TEST $CLI volume start $V0
d1681e
+
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 --attribute-timeout=0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+TEST mkdir tmp{1..10}
d1681e
+
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}3
d1681e
+EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "3" online_brick_count
d1681e
+
d1681e
+succ=fail=0
d1681e
+## set user.foo xattr with value newabc after kill one brick
d1681e
+set_fattr
d1681e
+TEST $CLI volume start $V0 force
d1681e
+EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "4" online_brick_count
d1681e
+
d1681e
+cd -
d1681e
+TEST umount $M0
d1681e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 --attribute-timeout=0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+## At this point dht code will heal xattr on down brick only for those dirs
d1681e
+## hashed subvol was up at the time of update xattr
d1681e
+TEST stat ./tmp{1..10}
d1681e
+
d1681e
+
d1681e
+## Count the user.foo xattr value with newabc on brick and compare with succ value
d1681e
+count=`getfattr -n user.foo $B0/${V0}3/tmp{1..10} | grep "user.foo" | grep -iw "newabc" | wc -l`
d1681e
+EXPECT "$succ" echo $count
d1681e
+
d1681e
+
d1681e
+cd -
d1681e
+cleanup
d1681e
+exit
d1681e
diff --git a/tests/bugs/bug-1371806_acl.t b/tests/bugs/bug-1371806_acl.t
d1681e
new file mode 100644
d1681e
index 0000000..aa41e04
d1681e
--- /dev/null
d1681e
+++ b/tests/bugs/bug-1371806_acl.t
d1681e
@@ -0,0 +1,90 @@
d1681e
+#!/bin/bash
d1681e
+. $(dirname $0)/../include.rc
d1681e
+. $(dirname $0)/../volume.rc
d1681e
+
d1681e
+cleanup;
d1681e
+TEST useradd tmpuser
d1681e
+
d1681e
+function set_facl_user {
d1681e
+        for i in `seq 1 10`
d1681e
+        do
d1681e
+                setfacl -m u:tmpuser:rw ./tmp${i}
d1681e
+                if [ "$?" = "0" ]
d1681e
+                 then
d1681e
+                    succ=$((succ+1))
d1681e
+                else
d1681e
+                    fail=$((fail+1))
d1681e
+                fi
d1681e
+        done
d1681e
+}
d1681e
+
d1681e
+function set_facl_default {
d1681e
+        for i in `seq 1 10`
d1681e
+        do
d1681e
+                setfacl -m d:o:rw ./tmp${i}
d1681e
+                if [ "$?" = "0" ]
d1681e
+                 then
d1681e
+                    succ1=$((succ1+1))
d1681e
+                else
d1681e
+                    fail1=$((fail1+1))
d1681e
+                fi
d1681e
+        done
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
+TEST glusterd
d1681e
+TEST pidof glusterd
d1681e
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3,4,5}
d1681e
+TEST $CLI volume set $V0 diagnostics.client-log-level DEBUG
d1681e
+TEST $CLI volume start $V0
d1681e
+
d1681e
+TEST glusterfs --volfile-id=$V0 --acl --volfile-server=$H0 --entry-timeout=0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+TEST mkdir tmp{1..10}
d1681e
+TEST setfacl -m u:tmpuser:rwx ./tmp{1..10}
d1681e
+count=`getfacl -p $M0/tmp{1..10} | grep -c "user:tmpuser:rwx"`
d1681e
+EXPECT "10" echo $count
d1681e
+TEST setfacl -m d:o:rwx ./tmp{1..10}
d1681e
+count=`getfacl -p $M0/tmp{1..10} | grep -c "default:other::rwx"`
d1681e
+EXPECT "10" echo $count
d1681e
+count=`getfacl -p $B0/${V0}5/tmp{1..10} | grep -c "user:tmpuser:rwx"`
d1681e
+EXPECT "10" echo $count
d1681e
+count=`getfacl -p $B0/${V0}5/tmp{1..10} | grep -c "default:other::rwx"`
d1681e
+EXPECT "10" echo $count
d1681e
+
d1681e
+
d1681e
+TEST kill_brick $V0 $H0 $B0/${V0}5
d1681e
+EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "5" online_brick_count
d1681e
+
d1681e
+succ=fail=0
d1681e
+## Update acl attributes on dir after kill one brick
d1681e
+set_facl_user
d1681e
+succ1=fail1=0
d1681e
+set_facl_default
d1681e
+
d1681e
+TEST $CLI volume start $V0 force
d1681e
+EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "6" online_brick_count
d1681e
+
d1681e
+cd -
d1681e
+TEST umount $M0
d1681e
+TEST glusterfs --volfile-id=$V0 --acl --volfile-server=$H0 --entry-timeout=0 $M0;
d1681e
+
d1681e
+cd $M0
d1681e
+## At this point dht will heal xatts on down brick only for those hashed_subvol
d1681e
+## was up at the time of updated xattrs
d1681e
+TEST stat ./tmp{1..10}
d1681e
+
d1681e
+## Compare succ value with updated acl attributes
d1681e
+count=`getfacl -p $B0/${V0}5/tmp{1..10} | grep -c "user:tmpuser:rw-"`
d1681e
+EXPECT "$succ" echo $count
d1681e
+
d1681e
+
d1681e
+count=`getfacl -p $B0/${V0}5/tmp{1..10} | grep -c "default:other::rw-"`
d1681e
+EXPECT "$succ1" echo $count
d1681e
+
d1681e
+cd -
d1681e
+userdel --force tmpuser
d1681e
+cleanup
d1681e
diff --git a/tests/bugs/distribute/bug-862967.t b/tests/bugs/distribute/bug-862967.t
d1681e
index 09dac37..2fb0848 100644
d1681e
--- a/tests/bugs/distribute/bug-862967.t
d1681e
+++ b/tests/bugs/distribute/bug-862967.t
d1681e
@@ -37,7 +37,7 @@ chown 1:1 $M0/dir;
d1681e
 
d1681e
 # Kill a brick process
d1681e
 
d1681e
-kill_brick $V0 $H0 $B0/${V0}1
d1681e
+kill_brick $V0 $H0 $B0/${V0}2
d1681e
 # change dir ownership
d1681e
 NEW_UID=36;
d1681e
 NEW_GID=36;
d1681e
@@ -51,9 +51,8 @@ sleep 10;
d1681e
 ls -l $M0/dir;
d1681e
 
d1681e
 # check if uid/gid is healed on backend brick which was taken down
d1681e
-BACKEND_UID=`stat -c %u $B0/${V0}1/dir`;
d1681e
-BACKEND_GID=`stat -c %g $B0/${V0}1/dir`;
d1681e
-
d1681e
+BACKEND_UID=`stat -c %u $B0/${V0}2/dir`;
d1681e
+BACKEND_GID=`stat -c %g $B0/${V0}2/dir`;
d1681e
 
d1681e
 EXPECT "0" uid_gid_compare $NEW_UID $NEW_GID $BACKEND_UID $BACKEND_GID
d1681e
 
d1681e
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
d1681e
index 5641330..f1e6a92 100644
d1681e
--- a/xlators/cluster/dht/src/dht-common.c
d1681e
+++ b/xlators/cluster/dht/src/dht-common.c
d1681e
@@ -110,6 +110,24 @@ int dht_read_iatt_from_xdata (xlator_t *this, dict_t *xdata,
d1681e
 int
d1681e
 dht_rmdir_unlock (call_frame_t *frame, xlator_t *this);
d1681e
 
d1681e
+char *xattrs_to_heal[] = {
d1681e
+        "user.",
d1681e
+        POSIX_ACL_ACCESS_XATTR,
d1681e
+        POSIX_ACL_DEFAULT_XATTR,
d1681e
+        QUOTA_LIMIT_KEY,
d1681e
+        QUOTA_LIMIT_OBJECTS_KEY,
d1681e
+        GF_SELINUX_XATTR_KEY,
d1681e
+        NULL
d1681e
+};
d1681e
+
d1681e
+/* Return true if key exists in array
d1681e
+*/
d1681e
+static gf_boolean_t
d1681e
+dht_match_xattr (const char *key)
d1681e
+{
d1681e
+        return gf_get_index_by_elem (xattrs_to_heal, (char *)key) >= 0;
d1681e
+}
d1681e
+
d1681e
 int
d1681e
 dht_aggregate_quota_xattr (dict_t *dst, char *key, data_t *value)
d1681e
 {
d1681e
@@ -205,7 +223,7 @@ int add_opt(char **optsp, const char *opt)
d1681e
 }
d1681e
 
d1681e
 /* Return Choice list from Split brain status */
d1681e
-char *
d1681e
+static char *
d1681e
 getChoices (const char *value)
d1681e
 {
d1681e
         int i = 0;
d1681e
@@ -428,6 +446,74 @@ out:
d1681e
         return;
d1681e
 }
d1681e
 
d1681e
+/* Code to save hashed subvol on inode ctx as a mds subvol
d1681e
+*/
d1681e
+int
d1681e
+dht_inode_ctx_mdsvol_set (inode_t *inode, xlator_t *this, xlator_t *mds_subvol)
d1681e
+{
d1681e
+        dht_inode_ctx_t         *ctx            = NULL;
d1681e
+        int                      ret            = -1;
d1681e
+        uint64_t                 ctx_int        = 0;
d1681e
+        gf_boolean_t             ctx_free       = _gf_false;
d1681e
+
d1681e
+
d1681e
+        LOCK (&inode->lock);
d1681e
+        {
d1681e
+                ret = __inode_ctx_get (inode, this , &ctx_int);
d1681e
+                if (ctx_int) {
d1681e
+                        ctx = (dht_inode_ctx_t *)ctx_int;
d1681e
+                        ctx->mds_subvol = mds_subvol;
d1681e
+                } else {
d1681e
+                        ctx = GF_CALLOC (1, sizeof(*ctx), gf_dht_mt_inode_ctx_t);
d1681e
+                        if (!ctx)
d1681e
+                                goto unlock;
d1681e
+                        ctx->mds_subvol = mds_subvol;
d1681e
+                        ctx_free        = _gf_true;
d1681e
+                        ctx_int = (long) ctx;
d1681e
+                        ret =  __inode_ctx_set (inode, this, &ctx_int);
d1681e
+                }
d1681e
+        }
d1681e
+unlock:
d1681e
+        UNLOCK (&inode->lock);
d1681e
+        if (ret && ctx_free)
d1681e
+                GF_FREE (ctx);
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
+/*Code to get mds subvol from inode ctx */
d1681e
+
d1681e
+int
d1681e
+dht_inode_ctx_mdsvol_get (inode_t *inode, xlator_t *this, xlator_t **mdsvol)
d1681e
+{
d1681e
+        dht_inode_ctx_t         *ctx            = NULL;
d1681e
+        int                      ret            = -1;
d1681e
+
d1681e
+        if (!mdsvol)
d1681e
+                return ret;
d1681e
+
d1681e
+        if (__is_root_gfid(inode->gfid)) {
d1681e
+                (*mdsvol) = FIRST_CHILD (this);
d1681e
+                return 0;
d1681e
+        }
d1681e
+
d1681e
+        ret = dht_inode_ctx_get (inode, this, &ctx;;
d1681e
+
d1681e
+        if (!ret && ctx) {
d1681e
+                if (ctx->mds_subvol) {
d1681e
+                        *mdsvol = ctx->mds_subvol;
d1681e
+                        ret = 0;
d1681e
+                } else {
d1681e
+                        ret = -1;
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
 /* TODO:
d1681e
    - use volumename in xattr instead of "dht"
d1681e
    - use NS locks
d1681e
@@ -443,6 +529,7 @@ dht_lookup_selfheal_cbk (call_frame_t *frame, void *cookie,
d1681e
 {
d1681e
         dht_local_t  *local = NULL;
d1681e
         dht_layout_t *layout = NULL;
d1681e
+        dht_conf_t   *conf   = NULL;
d1681e
         int           ret = -1;
d1681e
 
d1681e
         GF_VALIDATE_OR_GOTO ("dht", frame, out);
d1681e
@@ -450,6 +537,7 @@ dht_lookup_selfheal_cbk (call_frame_t *frame, void *cookie,
d1681e
         GF_VALIDATE_OR_GOTO ("dht", frame->local, out);
d1681e
 
d1681e
         local = frame->local;
d1681e
+        conf  = this->private;
d1681e
         ret = op_ret;
d1681e
 
d1681e
         FRAME_SU_UNDO (frame, dht_local_t);
d1681e
@@ -467,6 +555,8 @@ dht_lookup_selfheal_cbk (call_frame_t *frame, void *cookie,
d1681e
 
d1681e
         DHT_STRIP_PHASE1_FLAGS (&local->stbuf);
d1681e
         dht_set_fixed_dir_stat (&local->postparent);
d1681e
+        /* Delete mds xattr at the time of STACK UNWIND */
d1681e
+        GF_REMOVE_INTERNAL_XATTR (conf->mds_xattr_key, local->xattr);
d1681e
 
d1681e
         DHT_STACK_UNWIND (lookup, frame, ret, local->op_errno, local->inode,
d1681e
                           &local->stbuf, local->xattr, &local->postparent);
d1681e
@@ -492,10 +582,12 @@ dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
d1681e
         int              i               = 0;
d1681e
         loc_t            loc             = {0 };
d1681e
         int8_t           is_read_only    = 0, layout_anomalies = 0;
d1681e
+        char             gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
 
d1681e
         local = discover_frame->local;
d1681e
         layout = local->layout;
d1681e
         conf = this->private;
d1681e
+        gf_uuid_unparse(local->gfid, gfid_local);
d1681e
 
d1681e
         LOCK(&discover_frame->lock);
d1681e
         {
d1681e
@@ -507,6 +599,18 @@ dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
d1681e
         if (!main_frame)
d1681e
                 return 0;
d1681e
 
d1681e
+        /* Code to update all extended attributed from
d1681e
+           subvol to local->xattr on that internal xattr has found
d1681e
+        */
d1681e
+        if (conf->subvolume_cnt == 1)
d1681e
+                local->need_xattr_heal = 0;
d1681e
+        if (local->need_xattr_heal && (local->mds_xattr)) {
d1681e
+                dht_dir_set_heal_xattr (this, local, local->xattr,
d1681e
+                                        local->mds_xattr, NULL, NULL);
d1681e
+                dict_unref (local->mds_xattr);
d1681e
+                local->mds_xattr = NULL;
d1681e
+        }
d1681e
+
d1681e
         ret = dict_get_int8 (local->xattr_req, QUOTA_READ_ONLY_KEY,
d1681e
                              &is_read_only);
d1681e
         if (ret < 0)
d1681e
@@ -575,6 +679,26 @@ dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
d1681e
                 }
d1681e
         }
d1681e
 
d1681e
+        if (IA_ISDIR (local->stbuf.ia_type)) {
d1681e
+                /* Call function to save hashed subvol on inode ctx if
d1681e
+                   internal mds xattr is not present and all subvols are up
d1681e
+                */
d1681e
+                if (!local->op_ret && !__is_root_gfid (local->stbuf.ia_gfid))
d1681e
+                        (void) dht_mark_mds_subvolume (discover_frame, this);
d1681e
+
d1681e
+                if (local->need_xattr_heal && !heal_path) {
d1681e
+                        local->need_xattr_heal = 0;
d1681e
+                        ret =  dht_dir_xattr_heal (this, local);
d1681e
+                        if (ret)
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR,
d1681e
+                                        ret,
d1681e
+                                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                        "xattr heal failed for "
d1681e
+                                        "directory  gfid is %s ",
d1681e
+                                        gfid_local);
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
         if (source && (heal_path || layout_anomalies)) {
d1681e
                 gf_uuid_copy (loc.gfid, local->gfid);
d1681e
                 if (gf_uuid_is_null (loc.gfid)) {
d1681e
@@ -621,10 +745,14 @@ cleanup:
d1681e
         }
d1681e
 done:
d1681e
         dht_set_fixed_dir_stat (&local->postparent);
d1681e
+        /* Delete mds xattr at the time of STACK UNWIND */
d1681e
+        GF_REMOVE_INTERNAL_XATTR (conf->mds_xattr_key, local->xattr);
d1681e
+
d1681e
         DHT_STACK_UNWIND (lookup, main_frame, local->op_ret, local->op_errno,
d1681e
                           local->inode, &local->stbuf, local->xattr,
d1681e
                           &local->postparent);
d1681e
         return 0;
d1681e
+
d1681e
 out:
d1681e
         DHT_STACK_UNWIND (lookup, main_frame, -1, op_errno, NULL, NULL, NULL,
d1681e
                           NULL);
d1681e
@@ -633,6 +761,170 @@ out:
d1681e
 }
d1681e
 
d1681e
 int
d1681e
+dht_mds_internal_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                               int op_ret, int op_errno, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t  *local                   = NULL;
d1681e
+        xlator_t     *hashed_subvol           = NULL;
d1681e
+        dht_conf_t   *conf                    = NULL;
d1681e
+        int           ret                     = 0;
d1681e
+
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, frame, out);
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, frame->local, out);
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        hashed_subvol  = cookie;
d1681e
+        conf = this->private;
d1681e
+
d1681e
+        if (op_ret) {
d1681e
+                gf_msg_debug (this->name, op_ret,
d1681e
+                              "Failed to set %s on the MDS for path %s. ",
d1681e
+                              conf->mds_xattr_key, local->loc.path);
d1681e
+        } else {
d1681e
+               /* Save mds subvol on inode ctx */
d1681e
+                ret = dht_inode_ctx_mdsvol_set (local->inode, this,
d1681e
+                                                hashed_subvol);
d1681e
+                if (ret) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_SET_INODE_CTX_FAILED,
d1681e
+                                "Failed to set mds subvol on inode ctx"
d1681e
+                                " %s for %s", hashed_subvol->name,
d1681e
+                                local->loc.path);
d1681e
+                }
d1681e
+        }
d1681e
+out:
d1681e
+        DHT_STACK_DESTROY (frame);
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+/* Code to save hashed subvol on inode ctx only while no
d1681e
+   mds xattr is availble and all subvols are up for fresh
d1681e
+*/
d1681e
+int
d1681e
+dht_mark_mds_subvolume (call_frame_t *frame, xlator_t *this)
d1681e
+{
d1681e
+        dht_local_t  *local                   = NULL;
d1681e
+        xlator_t     *hashed_subvol           = NULL;
d1681e
+        int           i                       = 0;
d1681e
+        gf_boolean_t  vol_down                = _gf_false;
d1681e
+        dht_conf_t   *conf                    = 0;
d1681e
+        int           ret                     = -1;
d1681e
+        char          gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
+        dict_t       *xattrs                      = NULL;
d1681e
+        dht_local_t  *copy_local                  = NULL;
d1681e
+        call_frame_t *xattr_frame                 = NULL;
d1681e
+        int32_t       zero[1]                     = {0};
d1681e
+
d1681e
+
d1681e
+        GF_VALIDATE_OR_GOTO ("dht", frame, out);
d1681e
+        GF_VALIDATE_OR_GOTO ("dht", this, out);
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, frame->local, out);
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, this->private, out);
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        conf = this->private;
d1681e
+        gf_uuid_unparse(local->gfid, gfid_local);
d1681e
+
d1681e
+
d1681e
+        /* Code to update hashed subvol consider as a mds subvol
d1681e
+           and save on inode ctx if all subvols are up and no internal
d1681e
+           xattr has been set yet
d1681e
+        */
d1681e
+        if (!dict_get (local->xattr, conf->mds_xattr_key)) {
d1681e
+                /* It means no internal MDS xattr has been set yet
d1681e
+                */
d1681e
+                /* Check the status of all subvol are up
d1681e
+                */
d1681e
+                for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                        if (!conf->subvolume_status[i]) {
d1681e
+                                vol_down = _gf_true;
d1681e
+                                break;
d1681e
+                        }
d1681e
+                }
d1681e
+                if (vol_down) {
d1681e
+                        ret = 0;
d1681e
+                        gf_msg_debug (this->name, 0,
d1681e
+                                      "subvol %s is down. Unable to "
d1681e
+                                      " save mds subvol on inode for "
d1681e
+                                      " path %s gfid is %s " ,
d1681e
+                                      conf->subvolumes[i]->name, local->loc.path,
d1681e
+                                      gfid_local);
d1681e
+                       goto out;
d1681e
+                }
d1681e
+                /* Calculate hashed subvol based on inode and
d1681e
+                   parent inode
d1681e
+                */
d1681e
+                hashed_subvol = dht_inode_get_hashed_subvol (local->inode,
d1681e
+                                                             this, &local->loc);
d1681e
+                if (!hashed_subvol) {
d1681e
+                        gf_msg (this->name, GF_LOG_DEBUG, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "Failed to get hashed subvol for path %s"
d1681e
+                                " gfid is %s ",
d1681e
+                                local->loc.path, gfid_local);
d1681e
+                } else {
d1681e
+                        xattrs = dict_new ();
d1681e
+                        if (!xattrs) {
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR, ENOMEM,
d1681e
+                                        DHT_MSG_NO_MEMORY, "dict_new failed");
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        /* Add internal MDS xattr on disk for hashed subvol
d1681e
+                        */
d1681e
+                        ret = dht_dict_set_array (xattrs, conf->mds_xattr_key, zero, 1);
d1681e
+                        if (ret) {
d1681e
+                                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
d1681e
+                                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                                        "Failed to set dictionary"
d1681e
+                                        "  value:key = %s for "
d1681e
+                                        "path %s", conf->mds_xattr_key,
d1681e
+                                        local->loc.path);
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        xattr_frame = create_frame (this, this->ctx->pool);
d1681e
+                        if (!xattr_frame) {
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        copy_local = dht_local_init (xattr_frame, &(local->loc),
d1681e
+                                                     NULL, 0);
d1681e
+                        if (!copy_local) {
d1681e
+                                ret = -1;
d1681e
+                                DHT_STACK_DESTROY (xattr_frame);
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        copy_local->stbuf = local->stbuf;
d1681e
+                        if (!copy_local->inode)
d1681e
+                                copy_local->inode = inode_ref (local->inode);
d1681e
+                        gf_uuid_copy (copy_local->loc.gfid, local->gfid);
d1681e
+                        STACK_WIND_COOKIE (xattr_frame, dht_mds_internal_setxattr_cbk,
d1681e
+                                           hashed_subvol, hashed_subvol,
d1681e
+                                           hashed_subvol->fops->setxattr,
d1681e
+                                           &local->loc, xattrs, 0, NULL);
d1681e
+                        ret = 0;
d1681e
+                }
d1681e
+        } else {
d1681e
+                ret = 0;
d1681e
+                gf_msg_debug (this->name, 0,
d1681e
+                              "internal xattr %s is present on subvol"
d1681e
+                              "on path %s gfid is %s " , conf->mds_xattr_key,
d1681e
+                               local->loc.path, gfid_local);
d1681e
+        }
d1681e
+
d1681e
+
d1681e
+out:
d1681e
+        if (xattrs)
d1681e
+                dict_unref (xattrs);
d1681e
+       return ret;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+int
d1681e
 dht_discover_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                   int op_ret, int op_errno,
d1681e
                   inode_t *inode, struct iatt *stbuf, dict_t *xattr,
d1681e
@@ -644,11 +936,15 @@ dht_discover_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
         dht_layout_t *layout                  = NULL;
d1681e
         int           ret                     = -1;
d1681e
         int           is_dir                  = 0;
d1681e
+        int32_t       check_mds               = 0;
d1681e
         int           is_linkfile             = 0;
d1681e
         int           attempt_unwind          = 0;
d1681e
         dht_conf_t   *conf                    = 0;
d1681e
-        char         gfid_local[GF_UUID_BUF_SIZE]  = {0};
d1681e
-        char         gfid_node[GF_UUID_BUF_SIZE]  = {0};
d1681e
+        char          gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
+        char          gfid_node[GF_UUID_BUF_SIZE]  = {0};
d1681e
+        int32_t       mds_xattr_val[1]             = {0};
d1681e
+        int           errst                        = 0;
d1681e
+
d1681e
 
d1681e
         GF_VALIDATE_OR_GOTO ("dht", frame, out);
d1681e
         GF_VALIDATE_OR_GOTO ("dht", this, out);
d1681e
@@ -743,6 +1039,41 @@ dht_discover_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                 dht_iatt_merge (this, &local->stbuf, stbuf, prev);
d1681e
                 dht_iatt_merge (this, &local->postparent, postparent,
d1681e
                                 prev);
d1681e
+                if (!dict_get (xattr, conf->mds_xattr_key)) {
d1681e
+                        goto unlock;
d1681e
+                } else {
d1681e
+                        gf_msg_debug (this->name, 0,
d1681e
+                                      "internal xattr %s is present on subvol"
d1681e
+                                      "on path %s gfid is %s " ,
d1681e
+                                      conf->mds_xattr_key,
d1681e
+                                      local->loc.path, gfid_local);
d1681e
+                }
d1681e
+                check_mds = dht_dict_get_array (xattr, conf->mds_xattr_key,
d1681e
+                                                mds_xattr_val, 1, &errst);
d1681e
+                /* save mds subvol on inode ctx */
d1681e
+                ret = dht_inode_ctx_mdsvol_set (local->inode, this,
d1681e
+                                                prev);
d1681e
+                if (ret) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_SET_INODE_CTX_FAILED,
d1681e
+                                "Failed to set hashed subvol for %s vol is %s",
d1681e
+                                local->loc.path, prev->name);
d1681e
+                }
d1681e
+
d1681e
+                if ((check_mds < 0) && !errst) {
d1681e
+                        local->mds_xattr = dict_ref (xattr);
d1681e
+                        gf_msg_debug (this->name, 0,
d1681e
+                                      "Value of %s is not zero on mds subvol"
d1681e
+                                      "so xattr needs to be healed on non mds"
d1681e
+                                      " path is %s and vol name is %s "
d1681e
+                                      " gfid is %s" ,
d1681e
+                                      conf->mds_xattr_key,
d1681e
+                                      local->loc.path,
d1681e
+                                      prev->name, gfid_local);
d1681e
+                        local->need_xattr_heal = 1;
d1681e
+                        local->mds_subvol  = prev;
d1681e
+                }
d1681e
+
d1681e
         }
d1681e
 unlock:
d1681e
         UNLOCK (&frame->lock);
d1681e
@@ -841,6 +1172,99 @@ err:
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
+/* Get the value of key from dict in the bytewise and save in array after
d1681e
+   convert from network byte order to host byte order
d1681e
+*/
d1681e
+int32_t
d1681e
+dht_dict_get_array (dict_t *dict, char *key, int32_t value[], int32_t size, int *errst)
d1681e
+{
d1681e
+        void    *ptr          = NULL;
d1681e
+        int32_t len           = -1;
d1681e
+        int32_t vindex        = -1;
d1681e
+        int32_t err           = -1;
d1681e
+        int     ret          = 0;
d1681e
+
d1681e
+        if (dict == NULL) {
d1681e
+                (*errst) = -1;
d1681e
+                return -EINVAL;
d1681e
+        }
d1681e
+        err = dict_get_ptr_and_len(dict, key, &ptr, &len;;
d1681e
+        if (err != 0) {
d1681e
+                (*errst) = -1;
d1681e
+                return err;
d1681e
+        }
d1681e
+
d1681e
+        if (len != (size * sizeof (int32_t))) {
d1681e
+                (*errst) = -1;
d1681e
+                return -EINVAL;
d1681e
+        }
d1681e
+
d1681e
+        memset (value, 0, size * sizeof(int32_t));
d1681e
+        for (vindex = 0; vindex < size; vindex++) {
d1681e
+                value[vindex] = ntoh32(*((int32_t *)ptr + vindex));
d1681e
+                if (value[vindex] < 0)
d1681e
+                        ret = -1;
d1681e
+        }
d1681e
+
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+/* Code to call syntask to heal custom xattr from hashed subvol
d1681e
+   to non hashed subvol
d1681e
+*/
d1681e
+int
d1681e
+dht_dir_xattr_heal (xlator_t *this, dht_local_t *local)
d1681e
+{
d1681e
+        dht_local_t  *copy_local                  = NULL;
d1681e
+        call_frame_t *copy                        = NULL;
d1681e
+        int          ret                          = -1;
d1681e
+        char         gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
+
d1681e
+        if (local->gfid) {
d1681e
+                gf_uuid_unparse(local->gfid, gfid_local);
d1681e
+        } else {
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                        "No gfid exists for path %s "
d1681e
+                        "so healing xattr is not possible",
d1681e
+                        local->loc.path);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        copy = create_frame (this, this->ctx->pool);
d1681e
+        if (copy) {
d1681e
+                copy_local = dht_local_init (copy, &(local->loc), NULL, 0);
d1681e
+                if (!copy_local) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, ENOMEM,
d1681e
+                                DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                "Memory allocation failed "
d1681e
+                                "for path %s gfid %s ",
d1681e
+                                local->loc.path, gfid_local);
d1681e
+                        DHT_STACK_DESTROY (copy);
d1681e
+                } else {
d1681e
+                        copy_local->stbuf = local->stbuf;
d1681e
+                        gf_uuid_copy (copy_local->loc.gfid, local->gfid);
d1681e
+                        copy_local->mds_subvol = local->mds_subvol;
d1681e
+                        FRAME_SU_DO (copy, dht_local_t);
d1681e
+                        ret = synctask_new (this->ctx->env, dht_dir_heal_xattrs,
d1681e
+                                            dht_dir_heal_xattrs_done,
d1681e
+                                            copy, copy);
d1681e
+                        if (ret) {
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR, ENOMEM,
d1681e
+                                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                        "Synctask creation failed to heal xattr "
d1681e
+                                        "for path %s gfid %s ",
d1681e
+                                        local->loc.path, gfid_local);
d1681e
+                                DHT_STACK_DESTROY (copy);
d1681e
+                        }
d1681e
+                }
d1681e
+        }
d1681e
+out:
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
+
d1681e
 
d1681e
 int
d1681e
 dht_lookup_dir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
@@ -849,13 +1273,17 @@ dht_lookup_dir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                     struct iatt *postparent)
d1681e
 {
d1681e
         dht_local_t  *local                   = NULL;
d1681e
+        dht_conf_t   *conf                    = NULL;
d1681e
         int           this_call_cnt           = 0;
d1681e
         xlator_t     *prev                    = NULL;
d1681e
         dht_layout_t *layout                  = NULL;
d1681e
         int           ret                     = -1;
d1681e
         int           is_dir                  = 0;
d1681e
-        char         gfid_local[GF_UUID_BUF_SIZE]  = {0};
d1681e
-        char         gfid_node[GF_UUID_BUF_SIZE]  = {0};
d1681e
+        int32_t       check_mds               = 0;
d1681e
+        int           errst                   = 0;
d1681e
+        char          gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
+        char          gfid_node[GF_UUID_BUF_SIZE]  = {0};
d1681e
+        int32_t       mds_xattr_val[1]                 = {0};
d1681e
 
d1681e
         GF_VALIDATE_OR_GOTO ("dht", frame, out);
d1681e
         GF_VALIDATE_OR_GOTO ("dht", this, out);
d1681e
@@ -865,17 +1293,20 @@ dht_lookup_dir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
 
d1681e
         local = frame->local;
d1681e
         prev  = cookie;
d1681e
+        conf  = this->private;
d1681e
 
d1681e
         layout = local->layout;
d1681e
 
d1681e
-        if (!op_ret && gf_uuid_is_null (local->gfid))
d1681e
+        if (!op_ret && gf_uuid_is_null (local->gfid)) {
d1681e
                 memcpy (local->gfid, stbuf->ia_gfid, 16);
d1681e
+        }
d1681e
+        if (local->gfid)
d1681e
+                gf_uuid_unparse(local->gfid, gfid_local);
d1681e
 
d1681e
         /* Check if the gfid is different for file from other node */
d1681e
         if (!op_ret && gf_uuid_compare (local->gfid, stbuf->ia_gfid)) {
d1681e
 
d1681e
                 gf_uuid_unparse(stbuf->ia_gfid, gfid_node);
d1681e
-                gf_uuid_unparse(local->gfid, gfid_local);
d1681e
 
d1681e
                 gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
                         DHT_MSG_GFID_MISMATCH,
d1681e
@@ -930,6 +1361,41 @@ dht_lookup_dir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
 
d1681e
                 dht_iatt_merge (this, &local->stbuf, stbuf, prev);
d1681e
                 dht_iatt_merge (this, &local->postparent, postparent, prev);
d1681e
+
d1681e
+                if (!dict_get (xattr, conf->mds_xattr_key)) {
d1681e
+                        gf_msg_debug (this->name, 0,
d1681e
+                                      "Internal xattr %s is not present "
d1681e
+                                      " on path %s gfid is %s " ,
d1681e
+                                      conf->mds_xattr_key,
d1681e
+                                      local->loc.path, gfid_local);
d1681e
+                        goto unlock;
d1681e
+                } else {
d1681e
+                        /* Save mds subvol on inode ctx */
d1681e
+                        ret = dht_inode_ctx_mdsvol_set (local->inode, this,
d1681e
+                                                        prev);
d1681e
+                        if (ret) {
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                        DHT_MSG_SET_INODE_CTX_FAILED,
d1681e
+                                        "Failed to set hashed subvol for %s vol is %s",
d1681e
+                                        local->loc.path, prev->name);
d1681e
+                         }
d1681e
+                }
d1681e
+                check_mds = dht_dict_get_array (xattr, conf->mds_xattr_key,
d1681e
+                                                mds_xattr_val, 1, &errst);
d1681e
+                if ((check_mds < 0) && !errst) {
d1681e
+                        local->mds_xattr = dict_ref (xattr);
d1681e
+                        gf_msg_debug (this->name, 0,
d1681e
+                                      "Value of %s is not zero on hashed subvol "
d1681e
+                                      "so xattr needs to be heal on non hashed"
d1681e
+                                      " path is %s and vol name is %s "
d1681e
+                                      " gfid is %s" ,
d1681e
+                                      conf->mds_xattr_key,
d1681e
+                                      local->loc.path,
d1681e
+                                      prev->name, gfid_local);
d1681e
+                        local->need_xattr_heal = 1;
d1681e
+                        local->mds_subvol  = prev;
d1681e
+                }
d1681e
+
d1681e
         }
d1681e
 unlock:
d1681e
         UNLOCK (&frame->lock);
d1681e
@@ -938,7 +1404,20 @@ unlock:
d1681e
         this_call_cnt = dht_frame_return (frame);
d1681e
 
d1681e
         if (is_last_call (this_call_cnt)) {
d1681e
-                gf_uuid_copy (local->loc.gfid, local->gfid);
d1681e
+                /* No need to call xattr heal code if volume count is 1
d1681e
+                */
d1681e
+                if (conf->subvolume_cnt == 1)
d1681e
+                        local->need_xattr_heal = 0;
d1681e
+
d1681e
+                /* Code to update all extended attributed from hashed subvol
d1681e
+                   to local->xattr
d1681e
+                */
d1681e
+                if (local->need_xattr_heal && (local->mds_xattr)) {
d1681e
+                        dht_dir_set_heal_xattr (this, local, local->xattr,
d1681e
+                                                local->mds_xattr, NULL, NULL);
d1681e
+                        dict_unref (local->mds_xattr);
d1681e
+                        local->mds_xattr = NULL;
d1681e
+                }
d1681e
 
d1681e
                 if (local->need_selfheal) {
d1681e
                         local->need_selfheal = 0;
d1681e
@@ -957,6 +1436,9 @@ unlock:
d1681e
                         }
d1681e
 
d1681e
                         dht_layout_set (this, local->inode, layout);
d1681e
+                        if (!dict_get (local->xattr, conf->mds_xattr_key) ||
d1681e
+                            local->need_xattr_heal)
d1681e
+                                goto selfheal;
d1681e
                 }
d1681e
 
d1681e
                 if (local->inode) {
d1681e
@@ -971,6 +1453,8 @@ unlock:
d1681e
 
d1681e
                 DHT_STRIP_PHASE1_FLAGS (&local->stbuf);
d1681e
                 dht_set_fixed_dir_stat (&local->postparent);
d1681e
+                /* Delete mds xattr at the time of STACK UNWIND */
d1681e
+                GF_REMOVE_INTERNAL_XATTR (conf->mds_xattr_key, local->xattr);
d1681e
                 DHT_STACK_UNWIND (lookup, frame, local->op_ret, local->op_errno,
d1681e
                                   local->inode, &local->stbuf, local->xattr,
d1681e
                                   &local->postparent);
d1681e
@@ -1027,6 +1511,9 @@ dht_revalidate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
         char gfid[GF_UUID_BUF_SIZE] = {0};
d1681e
         uint32_t      vol_commit_hash = 0;
d1681e
         xlator_t      *subvol = NULL;
d1681e
+        int32_t       check_mds       = 0;
d1681e
+        int           errst           = 0;
d1681e
+        int32_t       mds_xattr_val[1] = {0};
d1681e
 
d1681e
         GF_VALIDATE_OR_GOTO ("dht", frame, err);
d1681e
         GF_VALIDATE_OR_GOTO ("dht", this, err);
d1681e
@@ -1051,6 +1538,9 @@ dht_revalidate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
 
d1681e
         LOCK (&frame->lock);
d1681e
         {
d1681e
+                if (gf_uuid_is_null (local->gfid)) {
d1681e
+                        memcpy (local->gfid, local->loc.gfid, 16);
d1681e
+                }
d1681e
 
d1681e
                 gf_msg_debug (this->name, op_errno,
d1681e
                               "revalidate lookup of %s "
d1681e
@@ -1136,6 +1626,7 @@ dht_revalidate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                                                 local->prebuf.ia_prot = stbuf->ia_prot;
d1681e
                                 }
d1681e
                         }
d1681e
+
d1681e
                         if (local->stbuf.ia_type != IA_INVAL)
d1681e
                         {
d1681e
                                 if ((local->stbuf.ia_gid != stbuf->ia_gid) ||
d1681e
@@ -1146,6 +1637,44 @@ dht_revalidate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                                         local->need_selfheal = 1;
d1681e
                                 }
d1681e
                         }
d1681e
+                        if (!dict_get (xattr, conf->mds_xattr_key)) {
d1681e
+                                gf_msg_debug (this->name, 0,
d1681e
+                                              "internal xattr %s is not present"
d1681e
+                                              " on path %s gfid is %s " ,
d1681e
+                                              conf->mds_xattr_key,
d1681e
+                                              local->loc.path, gfid);
d1681e
+                        } else {
d1681e
+                                check_mds = dht_dict_get_array (xattr, conf->mds_xattr_key,
d1681e
+                                                                mds_xattr_val, 1, &errst);
d1681e
+                                if (local->mds_subvol == prev) {
d1681e
+                                        local->mds_stbuf.ia_gid = stbuf->ia_gid;
d1681e
+                                        local->mds_stbuf.ia_uid = stbuf->ia_uid;
d1681e
+                                        local->mds_stbuf.ia_prot = stbuf->ia_prot;
d1681e
+                                }
d1681e
+                                /* save mds subvol on inode ctx */
d1681e
+                                ret = dht_inode_ctx_mdsvol_set (local->inode, this,
d1681e
+                                                                prev);
d1681e
+                                if (ret) {
d1681e
+                                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                                DHT_MSG_SET_INODE_CTX_FAILED,
d1681e
+                                                "Failed to set MDS subvol for %s vol is %s",
d1681e
+                                                local->loc.path, prev->name);
d1681e
+                                }
d1681e
+                                if ((check_mds < 0) && !errst) {
d1681e
+                                        local->mds_xattr = dict_ref (xattr);
d1681e
+                                        gf_msg_debug (this->name, 0,
d1681e
+                                                      "Value of %s is not zero on "
d1681e
+                                                      "hashed subvol so xattr needs to"
d1681e
+                                                      " be healed on non hashed"
d1681e
+                                                      " path is %s and vol name is %s "
d1681e
+                                                      " gfid is %s" ,
d1681e
+                                                      conf->mds_xattr_key,
d1681e
+                                                      local->loc.path,
d1681e
+                                                      prev->name, gfid);
d1681e
+                                        local->need_xattr_heal = 1;
d1681e
+                                        local->mds_subvol  = prev;
d1681e
+                                }
d1681e
+                        }
d1681e
                         ret = dht_layout_dir_mismatch (this, layout,
d1681e
                                                        prev, &local->loc,
d1681e
                                                        xattr);
d1681e
@@ -1215,13 +1744,52 @@ out:
d1681e
                     && (conf && conf->unhashed_sticky_bit)) {
d1681e
                         local->stbuf.ia_prot.sticky = 1;
d1681e
                 }
d1681e
+                /* No need to call heal code if volume count is 1
d1681e
+                */
d1681e
+                if (conf->subvolume_cnt == 1)
d1681e
+                        local->need_xattr_heal = 0;
d1681e
+
d1681e
+                /* Code to update all extended attributed from hashed subvol
d1681e
+                   to local->xattr
d1681e
+                */
d1681e
+                if (local->need_xattr_heal && (local->mds_xattr)) {
d1681e
+                        dht_dir_set_heal_xattr (this, local, local->xattr,
d1681e
+                                                local->mds_xattr, NULL, NULL);
d1681e
+                        dict_unref (local->mds_xattr);
d1681e
+                        local->mds_xattr = NULL;
d1681e
+                }
d1681e
+                /* Call function to save hashed subvol on inode ctx if
d1681e
+                   internal mds xattr is not present and all subvols are up
d1681e
+                */
d1681e
+                if (inode && !__is_root_gfid (inode->gfid) &&
d1681e
+                    (!local->op_ret) && (IA_ISDIR (local->stbuf.ia_type)))
d1681e
+                        (void) dht_mark_mds_subvolume (frame, this);
d1681e
+
d1681e
+                if (local->need_xattr_heal) {
d1681e
+                        local->need_xattr_heal = 0;
d1681e
+                        ret =  dht_dir_xattr_heal (this, local);
d1681e
+                        if (ret)
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR,
d1681e
+                                        ret, DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                        "xattr heal failed for directory %s "
d1681e
+                                        " gfid %s ", local->loc.path,
d1681e
+                                        gfid);
d1681e
+                }
d1681e
                 if (local->need_selfheal) {
d1681e
                         local->need_selfheal = 0;
d1681e
-                        gf_uuid_copy (local->gfid, local->stbuf.ia_gfid);
d1681e
-                        local->stbuf.ia_gid = local->prebuf.ia_gid;
d1681e
-                        local->stbuf.ia_uid = local->prebuf.ia_uid;
d1681e
-                        if (__is_root_gfid(local->stbuf.ia_gfid))
d1681e
+                        if (!__is_root_gfid (inode->gfid)) {
d1681e
+                                gf_uuid_copy (local->gfid, local->mds_stbuf.ia_gfid);
d1681e
+                                if (local->mds_stbuf.ia_gid || local->mds_stbuf.ia_uid) {
d1681e
+                                        local->stbuf.ia_gid = local->mds_stbuf.ia_gid;
d1681e
+                                        local->stbuf.ia_uid = local->mds_stbuf.ia_uid;
d1681e
+                                }
d1681e
+                        } else {
d1681e
+                                gf_uuid_copy (local->gfid, local->stbuf.ia_gfid);
d1681e
+                                local->stbuf.ia_gid = local->prebuf.ia_gid;
d1681e
+                                local->stbuf.ia_uid = local->prebuf.ia_uid;
d1681e
                                 local->stbuf.ia_prot = local->prebuf.ia_prot;
d1681e
+                        }
d1681e
+
d1681e
                         copy = create_frame (this, this->ctx->pool);
d1681e
                         if (copy) {
d1681e
                                 copy_local = dht_local_init (copy, &local->loc,
d1681e
@@ -1229,6 +1797,8 @@ out:
d1681e
                                 if (!copy_local)
d1681e
                                         goto cont;
d1681e
                                 copy_local->stbuf = local->stbuf;
d1681e
+                                copy_local->mds_stbuf = local->mds_stbuf;
d1681e
+                                copy_local->mds_subvol = local->mds_subvol;
d1681e
                                 copy->local = copy_local;
d1681e
                                 FRAME_SU_DO (copy, dht_local_t);
d1681e
                                 ret = synctask_new (this->ctx->env,
d1681e
@@ -1283,6 +1853,8 @@ cont:
d1681e
                         local->op_ret = -1;
d1681e
                         local->op_errno = ESTALE;
d1681e
                 }
d1681e
+                /* Delete mds xattr at the time of STACK UNWIND */
d1681e
+                GF_REMOVE_INTERNAL_XATTR (conf->mds_xattr_key, local->xattr);
d1681e
 
d1681e
                 DHT_STACK_UNWIND (lookup, frame, local->op_ret, local->op_errno,
d1681e
                                   local->inode, &local->stbuf, local->xattr,
d1681e
@@ -2303,6 +2875,62 @@ out:
d1681e
 
d1681e
 }
d1681e
 
d1681e
+/* Code to get hashed subvol based on inode and loc
d1681e
+   First it check if loc->parent and loc->path exist then it get
d1681e
+   hashed subvol based on loc.
d1681e
+*/
d1681e
+
d1681e
+xlator_t *
d1681e
+dht_inode_get_hashed_subvol (inode_t *inode, xlator_t *this, loc_t *loc)
d1681e
+{
d1681e
+        char                    *path           = NULL;
d1681e
+        loc_t                    populate_loc   = {0, };
d1681e
+        char                    *name           = NULL;
d1681e
+        xlator_t                *hash_subvol    = NULL;
d1681e
+
d1681e
+        if (!inode)
d1681e
+                return hash_subvol;
d1681e
+
d1681e
+        if (loc && loc->parent && loc->path) {
d1681e
+                if (!loc->name) {
d1681e
+                        name = strrchr (loc->path, '/');
d1681e
+                        if (name) {
d1681e
+                                loc->name = name + 1;
d1681e
+                        } else {
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                }
d1681e
+                hash_subvol = dht_subvol_get_hashed (this, loc);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        if (!gf_uuid_is_null (inode->gfid)) {
d1681e
+                populate_loc.inode = inode_ref (inode);
d1681e
+                populate_loc.parent = inode_parent (populate_loc.inode,
d1681e
+                                                    NULL, NULL);
d1681e
+                inode_path (populate_loc.inode, NULL, &path);
d1681e
+
d1681e
+                if (!path)
d1681e
+                        goto out;
d1681e
+
d1681e
+                populate_loc.path = path;
d1681e
+                if (!populate_loc.name && populate_loc.path) {
d1681e
+                        name = strrchr (populate_loc.path, '/');
d1681e
+                        if (name) {
d1681e
+                                populate_loc.name = name + 1;
d1681e
+
d1681e
+                        } else {
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                }
d1681e
+                hash_subvol = dht_subvol_get_hashed (this, &populate_loc);
d1681e
+        }
d1681e
+out:
d1681e
+        if (populate_loc.inode)
d1681e
+                loc_wipe (&populate_loc);
d1681e
+        return hash_subvol;
d1681e
+}
d1681e
+
d1681e
 
d1681e
 int
d1681e
 dht_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
@@ -2537,6 +3165,7 @@ dht_lookup (call_frame_t *frame, xlator_t *this,
d1681e
 {
d1681e
         xlator_t     *subvol = NULL;
d1681e
         xlator_t     *hashed_subvol = NULL;
d1681e
+        xlator_t     *mds_subvol = NULL;
d1681e
         dht_local_t  *local  = NULL;
d1681e
         dht_conf_t   *conf = NULL;
d1681e
         int           ret    = -1;
d1681e
@@ -2587,6 +3216,15 @@ dht_lookup (call_frame_t *frame, xlator_t *this,
d1681e
                 local->xattr_req = dict_new ();
d1681e
         }
d1681e
 
d1681e
+        ret = dict_set_uint32 (local->xattr_req, conf->mds_xattr_key, 4);
d1681e
+
d1681e
+        if (ret) {
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
d1681e
+                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                        "Failed to set dictionary value:key = %s for "
d1681e
+                        "path %s", conf->mds_xattr_key, loc->path);
d1681e
+        }
d1681e
+
d1681e
         /* Nameless lookup */
d1681e
 
d1681e
         if (gf_uuid_is_null (loc->pargfid) && !gf_uuid_is_null (loc->gfid) &&
d1681e
@@ -2663,6 +3301,14 @@ dht_lookup (call_frame_t *frame, xlator_t *this,
d1681e
                         goto err;
d1681e
                 }
d1681e
                 if (IA_ISDIR (local->inode->ia_type)) {
d1681e
+                        ret = dht_inode_ctx_mdsvol_get (local->inode, this,
d1681e
+                                                        &mds_subvol);
d1681e
+                        if (ret || !mds_subvol) {
d1681e
+                                gf_msg_debug (this->name, 0,
d1681e
+                                              "Failed to get mds subvol for path %s",
d1681e
+                                              local->loc.path);
d1681e
+                        }
d1681e
+                        local->mds_subvol = mds_subvol;
d1681e
                         local->call_cnt = call_cnt = conf->subvolume_cnt;
d1681e
                         for (i = 0; i < call_cnt; i++) {
d1681e
                                 STACK_WIND_COOKIE (frame, dht_revalidate_cbk,
d1681e
@@ -2851,76 +3497,300 @@ dht_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
 
d1681e
                 local->op_ret = 0;
d1681e
 
d1681e
-                local->postparent = *postparent;
d1681e
-                local->preparent = *preparent;
d1681e
+                local->postparent = *postparent;
d1681e
+                local->preparent = *preparent;
d1681e
+
d1681e
+                if (local->loc.parent) {
d1681e
+                        dht_inode_ctx_time_update (local->loc.parent, this,
d1681e
+                                                   &local->preparent, 0);
d1681e
+                        dht_inode_ctx_time_update (local->loc.parent, this,
d1681e
+                                                   &local->postparent, 1);
d1681e
+                }
d1681e
+        }
d1681e
+unlock:
d1681e
+        UNLOCK (&frame->lock);
d1681e
+
d1681e
+        if (!local->op_ret) {
d1681e
+                hashed_subvol = dht_subvol_get_hashed (this, &local->loc);
d1681e
+                if (hashed_subvol && hashed_subvol != local->cached_subvol) {
d1681e
+                        /*
d1681e
+                         * If hashed and cached are different, then we need
d1681e
+                         * to unlink linkfile from hashed subvol if data
d1681e
+                         * file is deleted successfully
d1681e
+                         */
d1681e
+                         STACK_WIND_COOKIE (frame, dht_unlink_linkfile_cbk,
d1681e
+                                            hashed_subvol, hashed_subvol,
d1681e
+                                            hashed_subvol->fops->unlink,
d1681e
+                                            &local->loc, local->flags, xdata);
d1681e
+                         return 0;
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
+        dht_set_fixed_dir_stat (&local->preparent);
d1681e
+        dht_set_fixed_dir_stat (&local->postparent);
d1681e
+        DHT_STACK_UNWIND (unlink, frame, local->op_ret, local->op_errno,
d1681e
+                          &local->preparent, &local->postparent, xdata);
d1681e
+
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+static int
d1681e
+dht_common_setxattr_cbk (call_frame_t *frame, void *cookie,
d1681e
+                         xlator_t *this, int32_t op_ret, int32_t op_errno,
d1681e
+                         dict_t *xdata)
d1681e
+{
d1681e
+         DHT_STACK_UNWIND (setxattr, frame, op_ret, op_errno, xdata);
d1681e
+         return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+int
d1681e
+dht_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+             int op_ret, int op_errno, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t  *local = NULL;
d1681e
+        int           this_call_cnt = 0;
d1681e
+        xlator_t     *prev = NULL;
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        prev = cookie;
d1681e
+
d1681e
+        LOCK (&frame->lock);
d1681e
+        {
d1681e
+                if (op_ret == -1) {
d1681e
+                        local->op_errno = op_errno;
d1681e
+                        gf_msg_debug (this->name, op_errno,
d1681e
+                                      "subvolume %s returned -1",
d1681e
+                                      prev->name);
d1681e
+                        goto unlock;
d1681e
+                }
d1681e
+
d1681e
+                local->op_ret = 0;
d1681e
+        }
d1681e
+unlock:
d1681e
+        UNLOCK (&frame->lock);
d1681e
+
d1681e
+        this_call_cnt = dht_frame_return (frame);
d1681e
+        if (is_last_call (this_call_cnt)) {
d1681e
+                DHT_STACK_UNWIND (setxattr, frame, local->op_ret,
d1681e
+                                  local->op_errno, NULL);
d1681e
+        }
d1681e
+
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+/* Set the value[] of key into dict after convert from
d1681e
+   host byte order to network byte order
d1681e
+*/
d1681e
+int32_t dht_dict_set_array (dict_t *dict, char *key, int32_t value[],
d1681e
+                            int32_t size)
d1681e
+{
d1681e
+        int         ret = -1;
d1681e
+        int32_t   *ptr = NULL;
d1681e
+        int32_t     vindex;
d1681e
+
d1681e
+        if (value == NULL) {
d1681e
+                return -EINVAL;
d1681e
+        }
d1681e
+
d1681e
+        ptr = GF_MALLOC(sizeof(int32_t) * size, gf_common_mt_char);
d1681e
+        if (ptr == NULL) {
d1681e
+                return -ENOMEM;
d1681e
+        }
d1681e
+        for (vindex = 0; vindex < size; vindex++) {
d1681e
+                ptr[vindex] = hton32(value[vindex]);
d1681e
+        }
d1681e
+        ret = dict_set_bin(dict, key, ptr, sizeof(int32_t) * size);
d1681e
+        if (ret)
d1681e
+                GF_FREE (ptr);
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
+/* Code to wind a xattrop call to add 1 on current mds internal xattr
d1681e
+   value
d1681e
+*/
d1681e
+int
d1681e
+dht_setxattr_non_mds_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                          int op_ret, int op_errno, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t  *local = NULL;
d1681e
+        int           this_call_cnt = 0;
d1681e
+        int           ret           = 0;
d1681e
+        dict_t        *xattrop      = NULL;
d1681e
+        int32_t       addone[1]     = {1};
d1681e
+        call_frame_t  *prev         = NULL;
d1681e
+        dht_conf_t    *conf         = NULL;
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        prev = cookie;
d1681e
+        conf = this->private;
d1681e
+
d1681e
+        LOCK (&frame->lock);
d1681e
+        {
d1681e
+             if (op_ret && !local->op_ret) {
d1681e
+                        local->op_ret = op_ret;
d1681e
+                        local->op_errno = op_errno;
d1681e
+                         gf_msg_debug (this->name, op_errno,
d1681e
+                                       "subvolume %s returned -1",
d1681e
+                                       prev->this->name);
d1681e
+             }
d1681e
+        }
d1681e
+        UNLOCK (&frame->lock);
d1681e
+        this_call_cnt = dht_frame_return (frame);
d1681e
+
d1681e
+        if (is_last_call (this_call_cnt)) {
d1681e
+                if (!local->op_ret) {
d1681e
+                        xattrop = dict_new ();
d1681e
+                        if (!xattrop) {
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR,
d1681e
+                                        DHT_MSG_NO_MEMORY, 0,
d1681e
+                                        "dictionary creation failed");
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        ret = dht_dict_set_array (xattrop,
d1681e
+                                                  conf->mds_xattr_key,
d1681e
+                                                  addone, 1);
d1681e
+                        if (ret != 0) {
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                                        "dictionary set array failed ");
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        if (local->fop == GF_FOP_SETXATTR) {
d1681e
+                                STACK_WIND (frame, dht_common_xattrop_cbk,
d1681e
+                                            local->mds_subvol,
d1681e
+                                            local->mds_subvol->fops->xattrop,
d1681e
+                                            &local->loc, GF_XATTROP_ADD_ARRAY,
d1681e
+                                            xattrop, NULL);
d1681e
+                        } else {
d1681e
+                                STACK_WIND (frame, dht_common_xattrop_cbk,
d1681e
+                                            local->mds_subvol,
d1681e
+                                            local->mds_subvol->fops->fxattrop,
d1681e
+                                            local->fd, GF_XATTROP_ADD_ARRAY,
d1681e
+                                            xattrop, NULL);
d1681e
+                        }
d1681e
+                } else  {
d1681e
+                        if (local->fop == GF_FOP_SETXATTR)
d1681e
+                                DHT_STACK_UNWIND (setxattr, frame, 0, 0, local->xdata);
d1681e
+                        else
d1681e
+                                DHT_STACK_UNWIND (fsetxattr, frame, 0, 0, local->xdata);
d1681e
+                }
d1681e
+        }
d1681e
+out:
d1681e
+        if (xattrop)
d1681e
+                dict_unref (xattrop);
d1681e
+        if (ret) {
d1681e
+                if (local->fop == GF_FOP_SETXATTR)
d1681e
+                        DHT_STACK_UNWIND (setxattr, frame, 0, 0, local->xdata);
d1681e
+                else
d1681e
+                        DHT_STACK_UNWIND (fsetxattr, frame, 0, 0, local->xdata);
d1681e
+        }
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+int
d1681e
+dht_setxattr_mds_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                      int op_ret, int op_errno, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t  *local = NULL;
d1681e
+        dht_conf_t   *conf  = NULL;
d1681e
+        call_frame_t *prev = NULL;
d1681e
+        xlator_t     *mds_subvol = NULL;
d1681e
+        int i = 0;
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        prev = cookie;
d1681e
+        conf = this->private;
d1681e
+        mds_subvol = local->mds_subvol;
d1681e
+
d1681e
+        if (op_ret == -1) {
d1681e
+                local->op_ret  = op_ret;
d1681e
+                local->op_errno = op_errno;
d1681e
+                gf_msg_debug (this->name, op_errno,
d1681e
+                              "subvolume %s returned -1",
d1681e
+                              prev->this->name);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        local->op_ret = 0;
d1681e
+        local->call_cnt = conf->subvolume_cnt - 1;
d1681e
+        local->xdata    = dict_ref (xdata);
d1681e
 
d1681e
-                if (local->loc.parent) {
d1681e
-                        dht_inode_ctx_time_update (local->loc.parent, this,
d1681e
-                                                   &local->preparent, 0);
d1681e
-                        dht_inode_ctx_time_update (local->loc.parent, this,
d1681e
-                                                   &local->postparent, 1);
d1681e
+        for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                if (mds_subvol && (mds_subvol == conf->subvolumes[i]))
d1681e
+                        continue;
d1681e
+                if (local->fop == GF_FOP_SETXATTR) {
d1681e
+                        STACK_WIND (frame, dht_setxattr_non_mds_cbk,
d1681e
+                                    conf->subvolumes[i],
d1681e
+                                    conf->subvolumes[i]->fops->setxattr,
d1681e
+                                    &local->loc, local->xattr,
d1681e
+                                    local->flags, local->xattr_req);
d1681e
+                } else {
d1681e
+                        STACK_WIND (frame, dht_setxattr_non_mds_cbk,
d1681e
+                                    conf->subvolumes[i],
d1681e
+                                    conf->subvolumes[i]->fops->fsetxattr,
d1681e
+                                    local->fd, local->xattr,
d1681e
+                                    local->flags, local->xattr_req);
d1681e
                 }
d1681e
         }
d1681e
-unlock:
d1681e
-        UNLOCK (&frame->lock);
d1681e
 
d1681e
-        if (!local->op_ret) {
d1681e
-                hashed_subvol = dht_subvol_get_hashed (this, &local->loc);
d1681e
-                if (hashed_subvol &&
d1681e
-                hashed_subvol != local->cached_subvol) {
d1681e
-                        /*
d1681e
-                         * If hashed and cached are different, then we need
d1681e
-                         * to unlink linkfile from hashed subvol if data
d1681e
-                         * file is deleted successfully
d1681e
-                         */
d1681e
-                        STACK_WIND_COOKIE (frame, dht_unlink_linkfile_cbk,
d1681e
-                                           hashed_subvol, hashed_subvol,
d1681e
-                                           hashed_subvol->fops->unlink, &local->loc,
d1681e
-                                           local->flags, xdata);
d1681e
-                        return 0;
d1681e
-                }
d1681e
+        return 0;
d1681e
+out:
d1681e
+        if (local->fop == GF_FOP_SETXATTR) {
d1681e
+                DHT_STACK_UNWIND (setxattr, frame, local->op_ret,
d1681e
+                                  local->op_errno, xdata);
d1681e
+        } else {
d1681e
+                DHT_STACK_UNWIND (fsetxattr, frame, local->op_ret,
d1681e
+                                  local->op_errno, xdata);
d1681e
         }
d1681e
 
d1681e
-        dht_set_fixed_dir_stat (&local->preparent);
d1681e
-        dht_set_fixed_dir_stat (&local->postparent);
d1681e
-        DHT_STACK_UNWIND (unlink, frame, local->op_ret, local->op_errno,
d1681e
-                          &local->preparent, &local->postparent, xdata);
d1681e
-
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
 int
d1681e
-dht_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
-             int op_ret, int op_errno, dict_t *xdata)
d1681e
+dht_xattrop_mds_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                     int op_ret, int op_errno, dict_t *dict, dict_t *xdata)
d1681e
 {
d1681e
         dht_local_t  *local = NULL;
d1681e
-        int           this_call_cnt = 0;
d1681e
-        xlator_t     *prev = NULL;
d1681e
+        call_frame_t *prev = NULL;
d1681e
 
d1681e
         local = frame->local;
d1681e
         prev = cookie;
d1681e
 
d1681e
-        LOCK (&frame->lock);
d1681e
-        {
d1681e
-                if (op_ret == -1) {
d1681e
-                        local->op_errno = op_errno;
d1681e
-                        gf_msg_debug (this->name, op_errno,
d1681e
-                                      "subvolume %s returned -1",
d1681e
-                                      prev->name);
d1681e
-                        goto unlock;
d1681e
-                }
d1681e
-
d1681e
-                local->op_ret = 0;
d1681e
+        if (op_ret == -1) {
d1681e
+                local->op_errno = op_errno;
d1681e
+                local->op_ret   = op_ret;
d1681e
+                gf_msg_debug (this->name, op_errno,
d1681e
+                              "subvolume %s returned -1",
d1681e
+                              prev->this->name);
d1681e
+                goto out;
d1681e
         }
d1681e
-unlock:
d1681e
-        UNLOCK (&frame->lock);
d1681e
 
d1681e
-        this_call_cnt = dht_frame_return (frame);
d1681e
-        if (is_last_call (this_call_cnt)) {
d1681e
-                DHT_STACK_UNWIND (setxattr, frame, local->op_ret,
d1681e
-                                  local->op_errno, NULL);
d1681e
+        if (local->fop == GF_FOP_SETXATTR) {
d1681e
+                STACK_WIND (frame, dht_setxattr_mds_cbk,
d1681e
+                            local->mds_subvol,
d1681e
+                            local->mds_subvol->fops->setxattr,
d1681e
+                            &local->loc, local->xattr,
d1681e
+                            local->flags, local->xattr_req);
d1681e
+        } else {
d1681e
+                STACK_WIND (frame, dht_setxattr_mds_cbk,
d1681e
+                            local->mds_subvol,
d1681e
+                            local->mds_subvol->fops->fsetxattr,
d1681e
+                            local->fd, local->xattr,
d1681e
+                            local->flags, local->xattr_req);
d1681e
         }
d1681e
-
d1681e
+        return 0;
d1681e
+out:
d1681e
+        if (local->fop == GF_FOP_SETXATTR)
d1681e
+                DHT_STACK_UNWIND (setxattr, frame, local->op_ret,
d1681e
+                                  local->op_errno, xdata);
d1681e
+        else
d1681e
+                DHT_STACK_UNWIND (fsetxattr, frame, local->op_ret,
d1681e
+                                  local->op_errno, xdata);
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
@@ -3371,6 +4241,41 @@ dht_linkinfo_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
+
d1681e
+int
d1681e
+dht_mds_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                      int op_ret, int op_errno, dict_t *xattr, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t     *local = NULL;
d1681e
+        dht_conf_t      *conf = NULL;
d1681e
+
d1681e
+        VALIDATE_OR_GOTO (frame, out);
d1681e
+        VALIDATE_OR_GOTO (frame->local, out);
d1681e
+        VALIDATE_OR_GOTO (this->private, out);
d1681e
+
d1681e
+        conf = this->private;
d1681e
+        local = frame->local;
d1681e
+
d1681e
+        if (!xattr || (op_ret == -1)) {
d1681e
+                local->op_ret = op_ret;
d1681e
+                goto out;
d1681e
+        }
d1681e
+        if (dict_get (xattr, conf->xattr_name)) {
d1681e
+                dict_del (xattr, conf->xattr_name);
d1681e
+        }
d1681e
+        local->op_ret = 0;
d1681e
+
d1681e
+        if (!local->xattr) {
d1681e
+                local->xattr = dict_copy_with_ref (xattr, NULL);
d1681e
+        }
d1681e
+
d1681e
+out:
d1681e
+        DHT_STACK_UNWIND (getxattr, frame, local->op_ret, op_errno,
d1681e
+                          local->xattr, xdata);
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
 int
d1681e
 dht_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                   int op_ret, int op_errno, dict_t *xattr, dict_t *xdata)
d1681e
@@ -3600,6 +4505,7 @@ dht_getxattr (call_frame_t *frame, xlator_t *this,
d1681e
 
d1681e
         xlator_t     *subvol        = NULL;
d1681e
         xlator_t     *hashed_subvol = NULL;
d1681e
+        xlator_t     *mds_subvol = NULL;
d1681e
         xlator_t     *cached_subvol = NULL;
d1681e
         dht_conf_t   *conf          = NULL;
d1681e
         dht_local_t  *local         = NULL;
d1681e
@@ -3642,6 +4548,12 @@ dht_getxattr (call_frame_t *frame, xlator_t *this,
d1681e
         }
d1681e
 
d1681e
         if (key &&
d1681e
+            (strncmp (key, conf->mds_xattr_key, strlen(key)) == 0)) {
d1681e
+                op_errno = ENOTSUP;
d1681e
+                goto err;
d1681e
+        }
d1681e
+
d1681e
+        if (key &&
d1681e
             (strncmp (key, GF_XATTR_GET_REAL_FILENAME_KEY,
d1681e
                       strlen (GF_XATTR_GET_REAL_FILENAME_KEY)) == 0)
d1681e
             && DHT_IS_DIR(layout)) {
d1681e
@@ -3771,26 +4683,53 @@ dht_getxattr (call_frame_t *frame, xlator_t *this,
d1681e
                 return 0;
d1681e
         }
d1681e
 
d1681e
-        if (key && (!strcmp (QUOTA_LIMIT_KEY, key) ||
d1681e
-                    !strcmp (QUOTA_LIMIT_OBJECTS_KEY, key))) {
d1681e
-                /* quota hardlimit and aggregated size of a directory is stored
d1681e
-                 * in inode contexts of each brick. Hence its good enough that
d1681e
-                 * we send getxattr for this key to any brick.
d1681e
-                 */
d1681e
-                local->call_cnt = 1;
d1681e
-                subvol = dht_first_up_subvol (this);
d1681e
-                STACK_WIND (frame, dht_getxattr_cbk, subvol,
d1681e
-                            subvol->fops->getxattr, loc, key, xdata);
d1681e
-                return 0;
d1681e
-        }
d1681e
-
d1681e
         if (cluster_handle_marker_getxattr (frame, loc, key, conf->vol_uuid,
d1681e
                                             dht_getxattr_unwind,
d1681e
                                             dht_marker_populate_args) == 0)
d1681e
                 return 0;
d1681e
 
d1681e
         if (DHT_IS_DIR(layout)) {
d1681e
-                cnt = local->call_cnt = layout->cnt;
d1681e
+                local->call_cnt = conf->subvolume_cnt;
d1681e
+                cnt = conf->subvolume_cnt;
d1681e
+                ret = dht_inode_ctx_mdsvol_get (loc->inode, this, &mds_subvol);
d1681e
+                if (!mds_subvol) {
d1681e
+                        gf_msg (this->name, GF_LOG_INFO, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "Cannot determine MDS, fetching xattr %s randomly"
d1681e
+                                " from a subvol for path %s ", key, loc->path);
d1681e
+                } else {
d1681e
+                        /* TODO need to handle it, As of now we are
d1681e
+                           choosing availability instead of chossing
d1681e
+                           consistencty, in case of mds_subvol is
d1681e
+                           down winding a getxattr call on other subvol
d1681e
+                           and return xattr
d1681e
+                        */
d1681e
+                        local->mds_subvol = mds_subvol;
d1681e
+                        for (i = 0; i < cnt; i++) {
d1681e
+                                if (conf->subvolumes[i] == mds_subvol) {
d1681e
+                                        if (!conf->subvolume_status[i]) {
d1681e
+                                                gf_msg (this->name,
d1681e
+                                                        GF_LOG_INFO, 0,
d1681e
+                                                        DHT_MSG_HASHED_SUBVOL_DOWN,
d1681e
+                                                        "MDS %s is down for path"
d1681e
+                                                        " path %s so fetching xattr "
d1681e
+                                                        "%s randomly from a subvol ",
d1681e
+                                                        local->mds_subvol->name,
d1681e
+                                                        loc->path, key);
d1681e
+                                                ret = 1;
d1681e
+                                        }
d1681e
+                                }
d1681e
+                        }
d1681e
+                }
d1681e
+
d1681e
+                if (!ret && key && local->mds_subvol && dht_match_xattr (key)) {
d1681e
+                        STACK_WIND (frame, dht_mds_getxattr_cbk,
d1681e
+                                    local->mds_subvol,
d1681e
+                                    local->mds_subvol->fops->getxattr,
d1681e
+                                    loc, key, xdata);
d1681e
+
d1681e
+                        return 0;
d1681e
+                }
d1681e
         } else {
d1681e
                 cnt = local->call_cnt  = 1;
d1681e
         }
d1681e
@@ -3821,6 +4760,10 @@ dht_fgetxattr (call_frame_t *frame, xlator_t *this,
d1681e
         int           op_errno      = -1;
d1681e
         int           i             = 0;
d1681e
         int           cnt           = 0;
d1681e
+        xlator_t      *mds_subvol = NULL;
d1681e
+        int           ret           = -1;
d1681e
+        dht_conf_t    *conf         = NULL;
d1681e
+        char           gfid[GF_UUID_BUF_SIZE] = {0};
d1681e
 
d1681e
         VALIDATE_OR_GOTO (frame, err);
d1681e
         VALIDATE_OR_GOTO (this, err);
d1681e
@@ -3828,6 +4771,8 @@ dht_fgetxattr (call_frame_t *frame, xlator_t *this,
d1681e
         VALIDATE_OR_GOTO (fd->inode, err);
d1681e
         VALIDATE_OR_GOTO (this->private, err);
d1681e
 
d1681e
+        conf = this->private;
d1681e
+
d1681e
         local = dht_local_init (frame, NULL, fd, GF_FOP_FGETXATTR);
d1681e
         if (!local) {
d1681e
                 op_errno = ENOMEM;
d1681e
@@ -3852,15 +4797,63 @@ dht_fgetxattr (call_frame_t *frame, xlator_t *this,
d1681e
                 }
d1681e
         }
d1681e
 
d1681e
+        if (fd->inode)
d1681e
+                gf_uuid_unparse(fd->inode->gfid, gfid);
d1681e
+
d1681e
         if ((fd->inode->ia_type == IA_IFDIR)
d1681e
             && key
d1681e
             && (strncmp (key, GF_XATTR_LOCKINFO_KEY,
d1681e
                          strlen (GF_XATTR_LOCKINFO_KEY)) != 0)) {
d1681e
-                cnt = local->call_cnt = layout->cnt;
d1681e
+                local->call_cnt = conf->subvolume_cnt;
d1681e
+                cnt             = conf->subvolume_cnt;
d1681e
+                ret = dht_inode_ctx_mdsvol_get (fd->inode, this, &mds_subvol);
d1681e
+
d1681e
+                if (!mds_subvol) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "cannot determine MDS, fetching xattr %s "
d1681e
+                                " randomly from a subvol for gfid %s ",
d1681e
+                                key, gfid);
d1681e
+                } else {
d1681e
+                        /* TODO need to handle it, As of now we are
d1681e
+                           choosing availability instead of chossing
d1681e
+                           consistencty, in case of hashed_subvol is
d1681e
+                           down winding a getxattr call on other subvol
d1681e
+                           and return xattr
d1681e
+                        */
d1681e
+                        local->mds_subvol = mds_subvol;
d1681e
+                        for (i = 0; i < cnt; i++) {
d1681e
+                                if (conf->subvolumes[i] == mds_subvol) {
d1681e
+                                        if (!conf->subvolume_status[i]) {
d1681e
+                                                gf_msg (this->name,
d1681e
+                                                        GF_LOG_WARNING, 0,
d1681e
+                                                        DHT_MSG_HASHED_SUBVOL_DOWN,
d1681e
+                                                        "MDS subvolume %s is down"
d1681e
+                                                        " for gfid %s so fetching xattr "
d1681e
+                                                        " %s randomly from a subvol ",
d1681e
+                                                        local->mds_subvol->name,
d1681e
+                                                        gfid, key);
d1681e
+                                                ret = 1;
d1681e
+                                        }
d1681e
+                                }
d1681e
+                        }
d1681e
+                }
d1681e
+
d1681e
+                if (!ret && key && local->mds_subvol &&
d1681e
+                    dht_match_xattr (key)) {
d1681e
+                        STACK_WIND (frame, dht_mds_getxattr_cbk,
d1681e
+                                    local->mds_subvol,
d1681e
+                                    local->mds_subvol->fops->fgetxattr,
d1681e
+                                    fd, key, NULL);
d1681e
+
d1681e
+                        return 0;
d1681e
+                }
d1681e
+
d1681e
         } else {
d1681e
                 cnt = local->call_cnt  = 1;
d1681e
         }
d1681e
 
d1681e
+
d1681e
         for (i = 0; i < cnt; i++) {
d1681e
                 subvol = layout->list[i].xlator;
d1681e
                 STACK_WIND (frame, dht_getxattr_cbk,
d1681e
@@ -3956,6 +4949,169 @@ out:
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
+/* Function is call by dict_foreach_fnmatch if key is match with
d1681e
+   user.* and set boolean flag to true
d1681e
+*/
d1681e
+static int
d1681e
+dht_is_user_xattr (dict_t *this, char *key, data_t *value, void *data)
d1681e
+{
d1681e
+        gf_boolean_t *user_xattr_found = data;
d1681e
+        *user_xattr_found = _gf_true;
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+/* Common code to wind a (f)setxattr call to set xattr on directory
d1681e
+*/
d1681e
+int
d1681e
+dht_dir_common_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc,
d1681e
+                         fd_t *fd, dict_t *xattr, int flags, dict_t *xdata,
d1681e
+                         int *op_errno)
d1681e
+
d1681e
+{
d1681e
+        dict_t       *xattrop             = NULL;
d1681e
+        int32_t       subone[1]            = {-1};
d1681e
+        gf_boolean_t  uxattr_key_found     = _gf_false;
d1681e
+        xlator_t     *mds_subvol          = NULL;
d1681e
+        xlator_t     *travvol              = NULL;
d1681e
+        dht_conf_t   *conf                = NULL;
d1681e
+        int           ret                  = -1;
d1681e
+        int           i                    = 0;
d1681e
+        int           call_cnt             = 0;
d1681e
+        dht_local_t  *local                = NULL;
d1681e
+        char          gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
+
d1681e
+        conf = this->private;
d1681e
+        local    = frame->local;
d1681e
+        call_cnt = conf->subvolume_cnt;
d1681e
+        local->flags = flags;
d1681e
+
d1681e
+        if (local->gfid)
d1681e
+                gf_uuid_unparse(local->gfid, gfid_local);
d1681e
+
d1681e
+        /* Check if any user xattr present in xattr
d1681e
+        */
d1681e
+        dict_foreach_fnmatch (xattr, "user*", dht_is_user_xattr,
d1681e
+                              &uxattr_key_found);
d1681e
+
d1681e
+        /* Check if any custom key xattr present in dict xattr
d1681e
+           and start index from 1 because user xattr already
d1681e
+           checked in previous line
d1681e
+        */
d1681e
+        for (i = 1; xattrs_to_heal[i]; i++)
d1681e
+                if (dict_get (xattr, xattrs_to_heal[i]))
d1681e
+                        uxattr_key_found = _gf_true;
d1681e
+
d1681e
+        /* If there is no custom key xattr present or gfid is root
d1681e
+           or call_cnt is 1 then wind a (f)setxattr call on all subvols
d1681e
+        */
d1681e
+        if (!uxattr_key_found || __is_root_gfid (local->gfid) || call_cnt == 1) {
d1681e
+                for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                        travvol = conf->subvolumes[i];
d1681e
+                        if (fd) {
d1681e
+                                STACK_WIND_COOKIE (frame, dht_err_cbk,
d1681e
+                                                   travvol, travvol,
d1681e
+                                                   travvol->fops->fsetxattr,
d1681e
+                                                   fd, xattr, flags, xdata);
d1681e
+                        } else {
d1681e
+                                STACK_WIND_COOKIE (frame, dht_err_cbk,
d1681e
+                                                   travvol, travvol,
d1681e
+                                                   travvol->fops->setxattr,
d1681e
+                                                   loc, xattr, flags, xdata);
d1681e
+                        }
d1681e
+                }
d1681e
+
d1681e
+                return 0;
d1681e
+        }
d1681e
+
d1681e
+        /* Calculate hash subvol based on inode and parent inode
d1681e
+         */
d1681e
+        if (fd) {
d1681e
+                ret = dht_inode_ctx_mdsvol_get (fd->inode, this, &mds_subvol);
d1681e
+        } else {
d1681e
+                ret = dht_inode_ctx_mdsvol_get (loc->inode, this, &mds_subvol);
d1681e
+        }
d1681e
+        if (ret || !mds_subvol) {
d1681e
+                if (fd) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "Failed to get mds subvol for fd %p"
d1681e
+                                "gfid is %s ", fd, gfid_local);
d1681e
+                } else {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "Failed to get mds subvol for path %s"
d1681e
+                                "gfid is %s ", loc->path, gfid_local);
d1681e
+                }
d1681e
+                (*op_errno) = ENOENT;
d1681e
+                goto err;
d1681e
+        }
d1681e
+
d1681e
+        local->mds_subvol = mds_subvol;
d1681e
+
d1681e
+        for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                if (conf->subvolumes[i] ==  mds_subvol) {
d1681e
+                        if (!conf->subvolume_status[i]) {
d1681e
+                                gf_msg (this->name, GF_LOG_WARNING,
d1681e
+                                        0, DHT_MSG_HASHED_SUBVOL_DOWN,
d1681e
+                                        "MDS subvol is down for path "
d1681e
+                                        " %s gfid is %s Unable to set xattr " ,
d1681e
+                                        local->loc.path, gfid_local);
d1681e
+                                (*op_errno) = ENOTCONN;
d1681e
+                                goto err;
d1681e
+                        }
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
+        if (uxattr_key_found) {
d1681e
+                xattrop = dict_new ();
d1681e
+                if (!xattrop) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, DHT_MSG_NO_MEMORY,
d1681e
+                                0, "dictionary creation failed for path %s "
d1681e
+                                "for gfid is %s ", local->loc.path, gfid_local);
d1681e
+                        (*op_errno) = ENOMEM;
d1681e
+                        goto err;
d1681e
+                }
d1681e
+                local->xattr = dict_ref (xattr);
d1681e
+                /* Subtract current MDS xattr value to -1 , value of MDS
d1681e
+                   xattr represents no. of times xattr modification failed
d1681e
+                   on non MDS subvols.
d1681e
+                */
d1681e
+                ret = dht_dict_set_array (xattrop, conf->mds_xattr_key, subone, 1);
d1681e
+                if (ret != 0) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0, DHT_MSG_DICT_SET_FAILED,
d1681e
+                                "dictionary set array failed for path %s "
d1681e
+                                "for gfid is %s ", local->loc.path, gfid_local);
d1681e
+                        if (xattrop)
d1681e
+                                dict_unref (xattrop);
d1681e
+                        (*op_errno) = ret;
d1681e
+                        goto err;
d1681e
+                }
d1681e
+                /* Wind a xattrop call to use ref counting approach
d1681e
+                   update mds xattr to -1 before update xattr on
d1681e
+                   hashed subvol and update mds xattr to +1 after update
d1681e
+                   xattr on all non hashed subvol
d1681e
+                */
d1681e
+                if (fd) {
d1681e
+                        STACK_WIND (frame, dht_xattrop_mds_cbk,
d1681e
+                                    local->mds_subvol,
d1681e
+                                    local->mds_subvol->fops->fxattrop,
d1681e
+                                     fd, GF_XATTROP_ADD_ARRAY, xattrop, NULL);
d1681e
+                } else {
d1681e
+                        STACK_WIND (frame, dht_xattrop_mds_cbk,
d1681e
+                                    local->mds_subvol,
d1681e
+                                    local->mds_subvol->fops->xattrop,
d1681e
+                                    loc, GF_XATTROP_ADD_ARRAY,
d1681e
+                                    xattrop, NULL);
d1681e
+                }
d1681e
+                if (xattrop)
d1681e
+                        dict_unref (xattrop);
d1681e
+        }
d1681e
+
d1681e
+        return 0;
d1681e
+err:
d1681e
+        return -1;
d1681e
+}
d1681e
 
d1681e
 
d1681e
 int
d1681e
@@ -3969,7 +5125,6 @@ dht_fsetxattr (call_frame_t *frame, xlator_t *this,
d1681e
         dht_layout_t *layout   = NULL;
d1681e
         int           ret      = -1;
d1681e
         int           call_cnt = 0;
d1681e
-        int           i        = 0;
d1681e
 
d1681e
         VALIDATE_OR_GOTO (frame, err);
d1681e
         VALIDATE_OR_GOTO (this, err);
d1681e
@@ -4009,14 +5164,11 @@ dht_fsetxattr (call_frame_t *frame, xlator_t *this,
d1681e
         local->call_cnt = call_cnt = layout->cnt;
d1681e
 
d1681e
         if (IA_ISDIR (fd->inode->ia_type)) {
d1681e
-                for (i = 0; i < call_cnt; i++) {
d1681e
-                        STACK_WIND_COOKIE (frame, dht_err_cbk,
d1681e
-                                           layout->list[i].xlator,
d1681e
-                                           layout->list[i].xlator,
d1681e
-                                           layout->list[i].xlator->fops->fsetxattr,
d1681e
-                                           fd, xattr, flags, xdata);
d1681e
-                }
d1681e
-
d1681e
+                local->hashed_subvol = NULL;
d1681e
+                ret = dht_dir_common_setxattr (frame, this, NULL, fd,
d1681e
+                                               xattr, flags, xdata, &op_errno);
d1681e
+                if (ret)
d1681e
+                        goto err;
d1681e
         } else {
d1681e
 
d1681e
                 local->call_cnt = 1;
d1681e
@@ -4043,16 +5195,6 @@ err:
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
-static int
d1681e
-dht_common_setxattr_cbk (call_frame_t *frame, void *cookie,
d1681e
-                         xlator_t *this, int32_t op_ret, int32_t op_errno,
d1681e
-                         dict_t *xdata)
d1681e
-{
d1681e
-        DHT_STACK_UNWIND (setxattr, frame, op_ret, op_errno, xdata);
d1681e
-
d1681e
-        return 0;
d1681e
-}
d1681e
-
d1681e
 
d1681e
 int
d1681e
 dht_checking_pathinfo_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
@@ -4190,6 +5332,7 @@ dht_nuke_dir (call_frame_t *frame, xlator_t *this, loc_t *loc, data_t *tmp)
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
+
d1681e
 int
d1681e
 dht_setxattr (call_frame_t *frame, xlator_t *this,
d1681e
               loc_t *loc, dict_t *xattr, int flags, dict_t *xdata)
d1681e
@@ -4209,6 +5352,7 @@ dht_setxattr (call_frame_t *frame, xlator_t *this,
d1681e
         int           call_cnt = 0;
d1681e
         uint32_t      new_hash = 0;
d1681e
 
d1681e
+
d1681e
         VALIDATE_OR_GOTO (frame, err);
d1681e
         VALIDATE_OR_GOTO (this, err);
d1681e
         VALIDATE_OR_GOTO (loc, err);
d1681e
@@ -4248,6 +5392,11 @@ dht_setxattr (call_frame_t *frame, xlator_t *this,
d1681e
         }
d1681e
 
d1681e
         local->call_cnt = call_cnt = layout->cnt;
d1681e
+        tmp = dict_get (xattr, conf->mds_xattr_key);
d1681e
+        if (tmp) {
d1681e
+                op_errno = ENOTSUP;
d1681e
+                goto err;
d1681e
+        }
d1681e
 
d1681e
         tmp = dict_get (xattr, GF_XATTR_FILE_MIGRATE_KEY);
d1681e
         if (tmp) {
d1681e
@@ -4423,15 +5572,11 @@ dht_setxattr (call_frame_t *frame, xlator_t *this,
d1681e
         local->xattr_req = xdata ? dict_ref (xdata) : dict_new ();
d1681e
 
d1681e
         if (IA_ISDIR (loc->inode->ia_type)) {
d1681e
-
d1681e
-                for (i = 0; i < call_cnt; i++) {
d1681e
-                        STACK_WIND_COOKIE (frame, dht_err_cbk,
d1681e
-                                           layout->list[i].xlator,
d1681e
-                                           layout->list[i].xlator,
d1681e
-                                           layout->list[i].xlator->fops->setxattr,
d1681e
-                                           loc, xattr, flags, xdata);
d1681e
-                }
d1681e
-
d1681e
+                local->hashed_subvol = NULL;
d1681e
+                ret = dht_dir_common_setxattr (frame, this, loc, NULL,
d1681e
+                                               xattr, flags, xdata, &op_errno);
d1681e
+                if (ret)
d1681e
+                        goto err;
d1681e
         } else {
d1681e
 
d1681e
                 local->rebalance.xattr = dict_ref (xattr);
d1681e
@@ -4670,6 +5815,12 @@ dht_removexattr (call_frame_t *frame, xlator_t *this,
d1681e
         local->call_cnt = call_cnt = layout->cnt;
d1681e
         local->key = gf_strdup (key);
d1681e
 
d1681e
+        if (key &&
d1681e
+            (strncmp (key, conf->mds_xattr_key, strlen(key)) == 0)) {
d1681e
+                op_errno = ENOTSUP;
d1681e
+                goto err;
d1681e
+        }
d1681e
+
d1681e
         if (IA_ISDIR (loc->inode->ia_type)) {
d1681e
                 for (i = 0; i < call_cnt; i++) {
d1681e
                         STACK_WIND_COOKIE (frame, dht_removexattr_cbk,
d1681e
@@ -7641,6 +8792,10 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie,
d1681e
         dht_iatt_merge (this, &local->postparent, postparent, prev);
d1681e
 
d1681e
         local->call_cnt = conf->subvolume_cnt - 1;
d1681e
+        /* Delete internal mds xattr from params dict to avoid store
d1681e
+          internal mds xattr on other subvols
d1681e
+        */
d1681e
+        dict_del (local->params, conf->mds_xattr_key);
d1681e
 
d1681e
         if (gf_uuid_is_null (local->loc.gfid))
d1681e
                 gf_uuid_copy (local->loc.gfid, stbuf->ia_gfid);
d1681e
@@ -7652,6 +8807,14 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie,
d1681e
                                         &local->loc, layout);
d1681e
         }
d1681e
 
d1681e
+        /* Set hashed subvol as a mds subvol on inode ctx */
d1681e
+        ret = dht_inode_ctx_mdsvol_set (local->inode, this, hashed_subvol);
d1681e
+        if (ret) {
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, 0, DHT_MSG_SET_INODE_CTX_FAILED,
d1681e
+                        "Failed to set hashed subvol for %s on inode vol is %s",
d1681e
+                        local->loc.path, hashed_subvol->name);
d1681e
+        }
d1681e
+
d1681e
         for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
                 if (conf->subvolumes[i] == hashed_subvol)
d1681e
                         continue;
d1681e
@@ -7661,6 +8824,7 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie,
d1681e
                                    &local->loc, local->mode, local->umask,
d1681e
                                    local->params);
d1681e
         }
d1681e
+
d1681e
         return 0;
d1681e
 err:
d1681e
         if (local->op_ret != 0) {
d1681e
@@ -7682,9 +8846,13 @@ dht_mkdir_guard_parent_layout_cbk (call_frame_t *frame, xlator_t *this,
d1681e
                                    dict_t *params)
d1681e
 {
d1681e
         dht_local_t *local                    = NULL;
d1681e
+        dht_conf_t  *conf                     = 0;
d1681e
         char          pgfid[GF_UUID_BUF_SIZE] = {0};
d1681e
+        int          ret                      = -1;
d1681e
+        int32_t      zero[1]                  = {0};
d1681e
 
d1681e
         local = frame->local;
d1681e
+        conf  = this->private;
d1681e
 
d1681e
         gf_uuid_unparse (loc->parent->gfid, pgfid);
d1681e
 
d1681e
@@ -7698,6 +8866,15 @@ dht_mkdir_guard_parent_layout_cbk (call_frame_t *frame, xlator_t *this,
d1681e
         }
d1681e
 
d1681e
         local->op_ret = -1;
d1681e
+        /* Add internal MDS xattr on disk for hashed subvol
d1681e
+        */
d1681e
+        ret = dht_dict_set_array (params, conf->mds_xattr_key, zero, 1);
d1681e
+        if (ret) {
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
d1681e
+                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                        "Failed to set dictionary value:key = %s for "
d1681e
+                        "path %s", conf->mds_xattr_key, loc->path);
d1681e
+        }
d1681e
 
d1681e
         STACK_WIND_COOKIE (frame, dht_mkdir_hashed_cbk, local->hashed_subvol,
d1681e
                            local->hashed_subvol,
d1681e
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h
d1681e
index 47a2e23..2aa7251 100644
d1681e
--- a/xlators/cluster/dht/src/dht-common.h
d1681e
+++ b/xlators/cluster/dht/src/dht-common.h
d1681e
@@ -28,6 +28,7 @@
d1681e
 #define GF_XATTR_FIX_LAYOUT_KEY         "distribute.fix.layout"
d1681e
 #define GF_XATTR_TIER_LAYOUT_FIXED_KEY  "trusted.tier.fix.layout.complete"
d1681e
 #define GF_XATTR_FILE_MIGRATE_KEY       "trusted.distribute.migrate-data"
d1681e
+#define DHT_MDS_STR                     "mds"
d1681e
 #define GF_DHT_LOOKUP_UNHASHED_ON       1
d1681e
 #define GF_DHT_LOOKUP_UNHASHED_AUTO     2
d1681e
 #define DHT_PATHINFO_HEADER             "DISTRIBUTE:"
d1681e
@@ -43,6 +44,12 @@
d1681e
 #define DHT_DIR_STAT_BLOCKS          8
d1681e
 #define DHT_DIR_STAT_SIZE            4096
d1681e
 
d1681e
+/* Array to hold custom xattr keys
d1681e
+*/
d1681e
+extern char *xattrs_to_heal[];
d1681e
+
d1681e
+
d1681e
+
d1681e
 #include <fnmatch.h>
d1681e
 
d1681e
 /* Array to hold custom xattr keys
d1681e
@@ -116,6 +123,7 @@ struct dht_inode_ctx {
d1681e
         dht_layout_t    *layout;
d1681e
         dht_stat_time_t  time;
d1681e
         xlator_t        *lock_subvol;
d1681e
+        xlator_t        *mds_subvol;     /* This is only used for directories */
d1681e
 };
d1681e
 
d1681e
 typedef struct dht_inode_ctx dht_inode_ctx_t;
d1681e
@@ -262,6 +270,7 @@ struct dht_local {
d1681e
         /* Use stbuf as the postbuf, when we require both
d1681e
          * pre and post attrs */
d1681e
         struct iatt              stbuf;
d1681e
+        struct iatt              mds_stbuf;
d1681e
         struct iatt              prebuf;
d1681e
         struct iatt              preoldparent;
d1681e
         struct iatt              postoldparent;
d1681e
@@ -273,6 +282,8 @@ struct dht_local {
d1681e
         inode_t                 *inode;
d1681e
         dict_t                  *params;
d1681e
         dict_t                  *xattr;
d1681e
+        dict_t                  *mds_xattr;
d1681e
+        dict_t                  *xdata;      /* dict used to save xdata response by xattr fop */
d1681e
         dict_t                  *xattr_req;
d1681e
         dht_layout_t            *layout;
d1681e
         size_t                   size;
d1681e
@@ -281,7 +292,9 @@ struct dht_local {
d1681e
         xlator_t                *dst_hashed, *dst_cached;
d1681e
         xlator_t                *cached_subvol;
d1681e
         xlator_t                *hashed_subvol;
d1681e
+        xlator_t                *mds_subvol; /* This is use for dir only */
d1681e
         char                     need_selfheal;
d1681e
+        char                     need_xattr_heal;
d1681e
         int                      file_count;
d1681e
         int                      dir_count;
d1681e
         call_frame_t            *main_frame;
d1681e
@@ -365,6 +378,9 @@ struct dht_local {
d1681e
 
d1681e
         /* fd open check */
d1681e
         gf_boolean_t fd_checked;
d1681e
+        /* This is use only for directory operation */
d1681e
+        int32_t valid;
d1681e
+        gf_boolean_t heal_layout;
d1681e
 };
d1681e
 typedef struct dht_local dht_local_t;
d1681e
 
d1681e
@@ -651,6 +667,7 @@ struct dht_conf {
d1681e
 
d1681e
         /* Support variable xattr names. */
d1681e
         char            *xattr_name;
d1681e
+        char            *mds_xattr_key;
d1681e
         char            *link_xattr_name;
d1681e
         char            *commithash_xattr_name;
d1681e
         char            *wild_xattr_name;
d1681e
@@ -1333,9 +1350,6 @@ dht_normalize_stats (struct statvfs *buf, unsigned long bsize,
d1681e
 int
d1681e
 add_opt(char **optsp, const char *opt);
d1681e
 
d1681e
-char *
d1681e
-getChoices (const char *value);
d1681e
-
d1681e
 int
d1681e
 dht_aggregate_split_brain_xattr (dict_t *dst, char *key, data_t *value);
d1681e
 
d1681e
@@ -1345,18 +1359,12 @@ dht_remove_stale_linkto (void *data);
d1681e
 int
d1681e
 dht_remove_stale_linkto_cbk (int ret, call_frame_t *sync_frame, void *data);
d1681e
 
d1681e
-
d1681e
 int
d1681e
 dht_fd_ctx_set (xlator_t *this, fd_t *fd, xlator_t *subvol);
d1681e
 
d1681e
 int
d1681e
 dht_check_and_open_fd_on_subvol (xlator_t *this, call_frame_t *frame);
d1681e
 
d1681e
-
d1681e
-
d1681e
-
d1681e
-
d1681e
-
d1681e
 /* FD fop callbacks */
d1681e
 
d1681e
 int
d1681e
@@ -1409,12 +1417,10 @@ int
d1681e
 dht_file_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                    int op_ret, int op_errno, struct iatt *stbuf, dict_t *xdata);
d1681e
 
d1681e
-
d1681e
 int
d1681e
 dht_file_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                           int op_ret, int op_errno, dict_t *xdata);
d1681e
 
d1681e
-
d1681e
 int
d1681e
 dht_file_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                        int op_ret, int op_errno, dict_t *xdata);
d1681e
@@ -1426,4 +1432,48 @@ int dht_request_iatt_in_xdata (xlator_t *this, dict_t *xattr_req);
d1681e
 
d1681e
 int dht_read_iatt_from_xdata (xlator_t *this, dict_t *xdata,
d1681e
                               struct iatt *stbuf);
d1681e
+
d1681e
+/* All custom xattr heal functions */
d1681e
+int
d1681e
+dht_dir_heal_xattrs (void *data);
d1681e
+
d1681e
+int
d1681e
+dht_dir_heal_xattrs_done (int ret, call_frame_t *sync_frame, void *data);
d1681e
+
d1681e
+void
d1681e
+dht_aggregate_xattr (dict_t *dst, dict_t *src);
d1681e
+
d1681e
+int32_t
d1681e
+dht_dict_set_array(dict_t *dict, char *key, int32_t value[], int32_t size);
d1681e
+
d1681e
+int
d1681e
+dht_set_user_xattr (dict_t *dict, char *k, data_t *v, void *data);
d1681e
+
d1681e
+void
d1681e
+dht_dir_set_heal_xattr (xlator_t *this, dht_local_t *local, dict_t *dst,
d1681e
+                        dict_t *src, int *uret, int *uflag);
d1681e
+
d1681e
+int
d1681e
+dht_dir_xattr_heal (xlator_t *this, dht_local_t *local);
d1681e
+
d1681e
+int32_t
d1681e
+dht_dict_get_array (dict_t *dict, char *key, int32_t value[], int32_t size, int *errst);
d1681e
+
d1681e
+xlator_t *
d1681e
+dht_inode_get_hashed_subvol (inode_t *inode, xlator_t *this, loc_t *loc);
d1681e
+
d1681e
+int
d1681e
+dht_mark_mds_subvolume (call_frame_t *frame, xlator_t *this);
d1681e
+
d1681e
+int
d1681e
+dht_mds_internal_setxattr_cbk (call_frame_t *frame, void *cookie,
d1681e
+                               xlator_t *this, int op_ret, int op_errno,
d1681e
+                               dict_t *xdata);
d1681e
+int
d1681e
+dht_inode_ctx_mdsvol_set (inode_t *inode, xlator_t *this,
d1681e
+                          xlator_t *mds_subvol);
d1681e
+int
d1681e
+dht_inode_ctx_mdsvol_get (inode_t *inode, xlator_t *this,
d1681e
+                          xlator_t **mdsvol);
d1681e
+
d1681e
 #endif/* _DHT_H */
d1681e
diff --git a/xlators/cluster/dht/src/dht-helper.c b/xlators/cluster/dht/src/dht-helper.c
d1681e
index e56a085..6e20aea 100644
d1681e
--- a/xlators/cluster/dht/src/dht-helper.c
d1681e
+++ b/xlators/cluster/dht/src/dht-helper.c
d1681e
@@ -767,6 +767,10 @@ dht_local_wipe (xlator_t *this, dht_local_t *local)
d1681e
 
d1681e
         if (local->xattr_req)
d1681e
                 dict_unref (local->xattr_req);
d1681e
+        if (local->mds_xattr)
d1681e
+                dict_unref (local->mds_xattr);
d1681e
+        if (local->xdata)
d1681e
+                dict_unref (local->xdata);
d1681e
 
d1681e
         if (local->selfheal.layout) {
d1681e
                 dht_layout_unref (this, local->selfheal.layout);
d1681e
@@ -2085,12 +2089,24 @@ dht_heal_full_path_done (int op_ret, call_frame_t *heal_frame, void *data)
d1681e
 
d1681e
         call_frame_t            *main_frame       = NULL;
d1681e
         dht_local_t             *local            = NULL;
d1681e
+        xlator_t                *this             = NULL;
d1681e
+        int                     ret               = -1;
d1681e
 
d1681e
         local = heal_frame->local;
d1681e
         main_frame = local->main_frame;
d1681e
         local->main_frame = NULL;
d1681e
+        this = heal_frame->this;
d1681e
 
d1681e
         dht_set_fixed_dir_stat (&local->postparent);
d1681e
+        if (local->need_xattr_heal) {
d1681e
+                local->need_xattr_heal = 0;
d1681e
+                ret =  dht_dir_xattr_heal (this, local);
d1681e
+                if (ret)
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, ret,
d1681e
+                                DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                "xattr heal failed for directory  %s ",
d1681e
+                                local->loc.path);
d1681e
+        }
d1681e
 
d1681e
         DHT_STACK_UNWIND (lookup, main_frame, 0, 0,
d1681e
                           local->inode, &local->stbuf, local->xattr,
d1681e
@@ -2254,3 +2270,52 @@ dht_lk_inode_unref (call_frame_t *frame, int32_t op_ret)
d1681e
 out:
d1681e
         return ret;
d1681e
 }
d1681e
+
d1681e
+/* Code to update custom extended attributes from src dict to dst dict
d1681e
+*/
d1681e
+void
d1681e
+dht_dir_set_heal_xattr (xlator_t *this, dht_local_t *local, dict_t *dst,
d1681e
+                        dict_t *src, int *uret, int *uflag)
d1681e
+{
d1681e
+        int               ret                 = -1;
d1681e
+        data_t           *keyval              = NULL;
d1681e
+        int               luret               = -1;
d1681e
+        int               luflag              = -1;
d1681e
+        int               i                   = 0;
d1681e
+
d1681e
+        if (!src || !dst) {
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, EINVAL,
d1681e
+                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                        "src or dst is NULL. Failed to set "
d1681e
+                        " dictionary value for path %s",
d1681e
+                        local->loc.path);
d1681e
+                return;
d1681e
+        }
d1681e
+        /* Check if any user xattr present in src dict and set
d1681e
+           it to dst dict
d1681e
+        */
d1681e
+        luret = dict_foreach_fnmatch (src, "user.*",
d1681e
+                                      dht_set_user_xattr, dst);
d1681e
+        /* Check if any other custom xattr present in src dict
d1681e
+           and set it to dst dict, here index start from 1 because
d1681e
+           user xattr already checked in previous statement
d1681e
+        */
d1681e
+        for (i = 1; xattrs_to_heal[i]; i++) {
d1681e
+                keyval = dict_get (src, xattrs_to_heal[i]);
d1681e
+                if (keyval) {
d1681e
+                        luflag = 1;
d1681e
+                        ret = dict_set (dst, xattrs_to_heal[i], keyval);
d1681e
+                        if (ret)
d1681e
+                                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
d1681e
+                                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                                        "Failed to set dictionary value:key = %s for "
d1681e
+                                        "path %s", xattrs_to_heal[i],
d1681e
+                                        local->loc.path);
d1681e
+                        keyval = NULL;
d1681e
+                }
d1681e
+        }
d1681e
+        if (uret)
d1681e
+                (*uret) = luret;
d1681e
+        if (uflag)
d1681e
+                (*uflag) = luflag;
d1681e
+}
d1681e
diff --git a/xlators/cluster/dht/src/dht-inode-write.c b/xlators/cluster/dht/src/dht-inode-write.c
d1681e
index 9709acf..7c596b1 100644
d1681e
--- a/xlators/cluster/dht/src/dht-inode-write.c
d1681e
+++ b/xlators/cluster/dht/src/dht-inode-write.c
d1681e
@@ -1161,6 +1161,7 @@ dht_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
                 dht_iatt_merge (this, &local->stbuf, statpost, prev);
d1681e
 
d1681e
                 local->op_ret = 0;
d1681e
+                local->op_errno = 0;
d1681e
         }
d1681e
 unlock:
d1681e
         UNLOCK (&frame->lock);
d1681e
@@ -1178,16 +1179,117 @@ unlock:
d1681e
 }
d1681e
 
d1681e
 
d1681e
+/* Keep the existing code same for all the cases other than regular file */
d1681e
+int
d1681e
+dht_non_mds_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                         int op_ret, int op_errno, struct iatt *statpre,
d1681e
+                         struct iatt *statpost, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t  *local = NULL;
d1681e
+        int           this_call_cnt = 0;
d1681e
+        xlator_t     *prev = NULL;
d1681e
+
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        prev = cookie;
d1681e
+
d1681e
+        LOCK (&frame->lock);
d1681e
+        {
d1681e
+                if (op_ret == -1) {
d1681e
+                        gf_msg (this->name, op_errno, 0,
d1681e
+                                0, "subvolume %s returned -1",
d1681e
+                                prev->name);
d1681e
+
d1681e
+                        goto unlock;
d1681e
+                }
d1681e
+
d1681e
+                dht_iatt_merge (this, &local->prebuf, statpre, prev);
d1681e
+                dht_iatt_merge (this, &local->stbuf, statpost, prev);
d1681e
+
d1681e
+                local->op_ret = 0;
d1681e
+                local->op_errno = 0;
d1681e
+        }
d1681e
+unlock:
d1681e
+        UNLOCK (&frame->lock);
d1681e
+
d1681e
+        this_call_cnt = dht_frame_return (frame);
d1681e
+        if (is_last_call (this_call_cnt)) {
d1681e
+                dht_inode_ctx_time_set (local->loc.inode, this, &local->stbuf);
d1681e
+                DHT_STACK_UNWIND (setattr, frame, 0, 0,
d1681e
+                                  &local->prebuf, &local->stbuf, xdata);
d1681e
+	}
d1681e
+
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
+int
d1681e
+dht_mds_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                     int op_ret, int op_errno, struct iatt *statpre,
d1681e
+                     struct iatt *statpost, dict_t *xdata)
d1681e
+
d1681e
+{
d1681e
+        dht_local_t  *local = NULL;
d1681e
+        dht_conf_t   *conf  = NULL;
d1681e
+        xlator_t     *prev = NULL;
d1681e
+        xlator_t     *mds_subvol = NULL;
d1681e
+        struct iatt  loc_stbuf = {0,};
d1681e
+        int i = 0;
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        prev = cookie;
d1681e
+        conf = this->private;
d1681e
+        mds_subvol = local->mds_subvol;
d1681e
+
d1681e
+        if (op_ret == -1) {
d1681e
+                local->op_ret  = op_ret;
d1681e
+                local->op_errno = op_errno;
d1681e
+                gf_msg_debug (this->name, op_errno,
d1681e
+                              "subvolume %s returned -1",
d1681e
+                              prev->name);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        local->op_ret = 0;
d1681e
+        loc_stbuf = local->stbuf;
d1681e
+        dht_iatt_merge (this, &local->prebuf, statpre, prev);
d1681e
+        dht_iatt_merge (this, &local->stbuf, statpost, prev);
d1681e
+
d1681e
+        local->call_cnt = conf->subvolume_cnt - 1;
d1681e
+        for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                if (mds_subvol == conf->subvolumes[i])
d1681e
+                        continue;
d1681e
+                STACK_WIND_COOKIE (frame, dht_non_mds_setattr_cbk,
d1681e
+                                   conf->subvolumes[i], conf->subvolumes[i],
d1681e
+                                   conf->subvolumes[i]->fops->setattr,
d1681e
+                                   &local->loc, &loc_stbuf,
d1681e
+                                   local->valid, local->xattr_req);
d1681e
+        }
d1681e
+
d1681e
+        return 0;
d1681e
+out:
d1681e
+        DHT_STACK_UNWIND (setattr, frame, local->op_ret, local->op_errno,
d1681e
+                          &local->prebuf, &local->stbuf, xdata);
d1681e
+
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
 int
d1681e
 dht_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc,
d1681e
              struct iatt *stbuf, int32_t valid, dict_t *xdata)
d1681e
 {
d1681e
-        xlator_t     *subvol = NULL;
d1681e
-        dht_layout_t *layout = NULL;
d1681e
-        dht_local_t  *local  = NULL;
d1681e
-        int           op_errno = -1;
d1681e
-        int           i = -1;
d1681e
-        int           call_cnt = 0;
d1681e
+        xlator_t     *subvol     = NULL;
d1681e
+        xlator_t     *mds_subvol = NULL;
d1681e
+        dht_layout_t *layout     = NULL;
d1681e
+        dht_local_t  *local      = NULL;
d1681e
+        int           op_errno   = -1;
d1681e
+        int           i          = -1;
d1681e
+        int           ret        = -1;
d1681e
+        int           call_cnt   = 0;
d1681e
+        dht_conf_t   *conf       = NULL;
d1681e
 
d1681e
         VALIDATE_OR_GOTO (frame, err);
d1681e
         VALIDATE_OR_GOTO (this, err);
d1681e
@@ -1195,6 +1297,7 @@ dht_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc,
d1681e
         VALIDATE_OR_GOTO (loc->inode, err);
d1681e
         VALIDATE_OR_GOTO (loc->path, err);
d1681e
 
d1681e
+        conf = this->private;
d1681e
         local = dht_local_init (frame, loc, NULL, GF_FOP_SETATTR);
d1681e
         if (!local) {
d1681e
                 op_errno = ENOMEM;
d1681e
@@ -1235,12 +1338,50 @@ dht_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc,
d1681e
 
d1681e
         local->call_cnt = call_cnt = layout->cnt;
d1681e
 
d1681e
-        for (i = 0; i < call_cnt; i++) {
d1681e
-                STACK_WIND_COOKIE (frame, dht_setattr_cbk,
d1681e
-                                   layout->list[i].xlator,
d1681e
-                                   layout->list[i].xlator,
d1681e
-                                   layout->list[i].xlator->fops->setattr,
d1681e
+        if (IA_ISDIR (loc->inode->ia_type) &&
d1681e
+            !__is_root_gfid (loc->inode->gfid) && call_cnt != 1) {
d1681e
+                ret = dht_inode_ctx_mdsvol_get (loc->inode, this, &mds_subvol);
d1681e
+                if (ret || !mds_subvol) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "Failed to get mds subvol for path %s",
d1681e
+                                local->loc.path);
d1681e
+                        op_errno = EINVAL;
d1681e
+                        goto err;
d1681e
+                }
d1681e
+
d1681e
+                local->mds_subvol = mds_subvol;
d1681e
+                for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                        if (conf->subvolumes[i] ==  mds_subvol) {
d1681e
+                                if (!conf->subvolume_status[i]) {
d1681e
+                                        gf_msg (this->name, GF_LOG_WARNING,
d1681e
+                                                layout->list[i].err,
d1681e
+                                                DHT_MSG_HASHED_SUBVOL_DOWN,
d1681e
+                                                "MDS subvol is down for path "
d1681e
+                                                " %s Unable to set attr " ,
d1681e
+                                                local->loc.path);
d1681e
+                                        op_errno = ENOTCONN;
d1681e
+                                        goto err;
d1681e
+                                }
d1681e
+                        }
d1681e
+                }
d1681e
+                local->valid = valid;
d1681e
+                local->stbuf = *stbuf;
d1681e
+
d1681e
+                STACK_WIND_COOKIE (frame, dht_mds_setattr_cbk,
d1681e
+                                   local->mds_subvol,
d1681e
+                                   local->mds_subvol,
d1681e
+                                   local->mds_subvol->fops->setattr,
d1681e
                                    loc, stbuf, valid, xdata);
d1681e
+                return 0;
d1681e
+        } else {
d1681e
+                for (i = 0; i < call_cnt; i++) {
d1681e
+                        STACK_WIND_COOKIE (frame, dht_setattr_cbk,
d1681e
+                                           layout->list[i].xlator,
d1681e
+                                           layout->list[i].xlator,
d1681e
+                                           layout->list[i].xlator->fops->setattr,
d1681e
+                                           loc, stbuf, valid, xdata);
d1681e
+                }
d1681e
         }
d1681e
 
d1681e
         return 0;
d1681e
diff --git a/xlators/cluster/dht/src/dht-messages.h b/xlators/cluster/dht/src/dht-messages.h
d1681e
index dcfd747..ade32e4 100644
d1681e
--- a/xlators/cluster/dht/src/dht-messages.h
d1681e
+++ b/xlators/cluster/dht/src/dht-messages.h
d1681e
@@ -40,7 +40,7 @@
d1681e
  */
d1681e
 
d1681e
 #define GLFS_DHT_BASE                   GLFS_MSGID_COMP_DHT
d1681e
-#define GLFS_DHT_NUM_MESSAGES           126
d1681e
+#define GLFS_DHT_NUM_MESSAGES           129
d1681e
 #define GLFS_MSGID_END          (GLFS_DHT_BASE + GLFS_DHT_NUM_MESSAGES + 1)
d1681e
 
d1681e
 /* Messages with message IDs */
d1681e
@@ -1083,6 +1083,7 @@
d1681e
  * @diagnosis
d1681e
  * @recommendedaction None
d1681e
  */
d1681e
+
d1681e
 #define DHT_MSG_DIR_LOOKUP_FAILED          (GLFS_DHT_BASE + 118)
d1681e
 
d1681e
 /*
d1681e
@@ -1111,6 +1112,7 @@
d1681e
  * @diagnosis
d1681e
  * @recommendedaction None
d1681e
  */
d1681e
+
d1681e
 #define DHT_MSG_ENTRYLK_ERROR          (GLFS_DHT_BASE + 122)
d1681e
 
d1681e
 /*
d1681e
@@ -1132,7 +1134,7 @@
d1681e
  * @diagnosis
d1681e
  * @recommendedaction None
d1681e
  */
d1681e
-#define DHT_MSG_UNKNOWN_FOP            (GLFS_DHT_BASE + 125)
d1681e
+#define DHT_MSG_UNKNOWN_FOP                     (GLFS_DHT_BASE + 125)
d1681e
 
d1681e
 /*
d1681e
  * @messageid 109126
d1681e
@@ -1141,5 +1143,27 @@
d1681e
  */
d1681e
 #define DHT_MSG_MIGRATE_FILE_SKIPPED        (GLFS_DHT_BASE + 126)
d1681e
 
d1681e
+/*
d1681e
+ * @messageid 109127
d1681e
+ * @diagnosis
d1681e
+ * @recommendedaction None
d1681e
+ */
d1681e
+#define DHT_MSG_DIR_XATTR_HEAL_FAILED           (GLFS_DHT_BASE + 127)
d1681e
+
d1681e
+/*
d1681e
+ * @messageid 109128
d1681e
+ * @diagnosis
d1681e
+ * @recommendedaction None
d1681e
+ */
d1681e
+#define DHT_MSG_HASHED_SUBVOL_DOWN             (GLFS_DHT_BASE + 128)
d1681e
+
d1681e
+/*
d1681e
+ * @messageid 109129
d1681e
+ * @diagnosis
d1681e
+ * @recommendedaction None
d1681e
+ */
d1681e
+#define DHT_MSG_NON_HASHED_SUBVOL_DOWN             (GLFS_DHT_BASE + 129)
d1681e
+
d1681e
+
d1681e
 #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
d1681e
 #endif /* _DHT_MESSAGES_H_ */
d1681e
diff --git a/xlators/cluster/dht/src/dht-selfheal.c b/xlators/cluster/dht/src/dht-selfheal.c
d1681e
index 3b9fcf1..328251d 100644
d1681e
--- a/xlators/cluster/dht/src/dht-selfheal.c
d1681e
+++ b/xlators/cluster/dht/src/dht-selfheal.c
d1681e
@@ -703,6 +703,18 @@ dht_selfheal_dir_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
+/* Code is required to set user xattr to local->xattr
d1681e
+*/
d1681e
+int
d1681e
+dht_set_user_xattr (dict_t *dict, char *k, data_t *v, void *data)
d1681e
+{
d1681e
+        dict_t          *set_xattr          = data;
d1681e
+        int              ret                = -1;
d1681e
+
d1681e
+        ret = dict_set (set_xattr, k, v);
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
 
d1681e
 int
d1681e
 dht_selfheal_dir_xattr_persubvol (call_frame_t *frame, loc_t *loc,
d1681e
@@ -830,7 +842,6 @@ dht_selfheal_dir_xattr_persubvol (call_frame_t *frame, loc_t *loc,
d1681e
 err:
d1681e
         if (xattr)
d1681e
                 dict_unref (xattr);
d1681e
-
d1681e
         if (xdata)
d1681e
                 dict_unref (xdata);
d1681e
 
d1681e
@@ -1128,6 +1139,14 @@ dht_selfheal_dir_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
         this_call_cnt = dht_frame_return (frame);
d1681e
 
d1681e
         if (is_last_call (this_call_cnt)) {
d1681e
+                if (!local->heal_layout) {
d1681e
+                        gf_msg_trace (this->name, 0,
d1681e
+                                      "Skip heal layout for %s gfid = %s ",
d1681e
+                                      local->loc.path, uuid_utoa(local->gfid));
d1681e
+
d1681e
+                        dht_selfheal_dir_finish (frame, this, 0, 1);
d1681e
+                        return 0;
d1681e
+                }
d1681e
                 ret = dht_selfheal_layout_lock (frame, layout, _gf_false,
d1681e
                                                 dht_selfheal_dir_xattr,
d1681e
                                                 dht_should_heal_layout);
d1681e
@@ -1140,6 +1159,141 @@ dht_selfheal_dir_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
         return 0;
d1681e
 }
d1681e
 
d1681e
+int
d1681e
+dht_selfheal_dir_check_set_mdsxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
d1681e
+                                         int op_ret, int op_errno, dict_t *xdata)
d1681e
+{
d1681e
+        dht_local_t  *local = NULL;
d1681e
+        xlator_t     *prev  = cookie;
d1681e
+        int           ret   = -1;
d1681e
+        dht_conf_t   *conf  = 0;
d1681e
+
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, frame, out);
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, frame->local, out);
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        conf = this->private;
d1681e
+
d1681e
+        if (op_ret) {
d1681e
+                gf_msg_debug (this->name, op_ret,
d1681e
+                              "internal mds setxattr %s is failed on mds subvol "
d1681e
+                              "at the time of heal on path %s " ,
d1681e
+                               conf->mds_xattr_key, local->loc.path);
d1681e
+        } else {
d1681e
+                /* Save mds subvol on inode ctx */
d1681e
+                ret = dht_inode_ctx_mdsvol_set (local->inode, this, prev);
d1681e
+                if (ret) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_SET_INODE_CTX_FAILED,
d1681e
+                                "Failed to set hashed subvol "
d1681e
+                                " %s for %s ", prev->name,
d1681e
+                                local->loc.path);
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
+out:
d1681e
+        DHT_STACK_DESTROY (frame);
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+/* Code to set internal mds xattr if it is not present
d1681e
+*/
d1681e
+int
d1681e
+dht_selfheal_dir_check_set_mdsxattr (call_frame_t *frame, loc_t *loc)
d1681e
+{
d1681e
+        dht_local_t  *local          = NULL;
d1681e
+        xlator_t     *this           = NULL;
d1681e
+        xlator_t     *hashed_subvol  = NULL;
d1681e
+        int ret                      = -1;
d1681e
+        dict_t       *xattrs         = NULL;
d1681e
+        char          gfid_local[GF_UUID_BUF_SIZE] = {0,};
d1681e
+        int32_t       zero[1]        = {0};
d1681e
+        call_frame_t *xattr_frame    = NULL;
d1681e
+        dht_local_t  *copy_local     = NULL;
d1681e
+        dht_conf_t   *conf           = 0;
d1681e
+
d1681e
+        local = frame->local;
d1681e
+        this = frame->this;
d1681e
+        conf = this->private;
d1681e
+        gf_uuid_unparse(local->gfid, gfid_local);
d1681e
+
d1681e
+        if (!dict_get (local->xattr, conf->mds_xattr_key)) {
d1681e
+                /* It means no internal MDS xattr has been set yet
d1681e
+                */
d1681e
+                /* Calculate hashed subvol based on inode and
d1681e
+                   parent inode
d1681e
+                */
d1681e
+                hashed_subvol = dht_inode_get_hashed_subvol (local->inode, this,
d1681e
+                                                             loc);
d1681e
+                if (!hashed_subvol) {
d1681e
+                        gf_msg (this->name, GF_LOG_DEBUG, 0,
d1681e
+                                DHT_MSG_HASHED_SUBVOL_GET_FAILED,
d1681e
+                                "Failed to get hashed subvol for path %s"
d1681e
+                                "gfid is %s ",
d1681e
+                                local->loc.path, gfid_local);
d1681e
+                        ret = -1;
d1681e
+                        goto out;
d1681e
+                } else {
d1681e
+                        /* Set internal mds xattr on disk   */
d1681e
+                        xattrs = dict_new ();
d1681e
+                        if (!xattrs) {
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR, ENOMEM,
d1681e
+                                        DHT_MSG_NO_MEMORY, "dict_new failed");
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        /* Add internal MDS xattr on disk for hashed subvol
d1681e
+                        */
d1681e
+                        ret = dht_dict_set_array (xattrs, conf->mds_xattr_key, zero, 1);
d1681e
+                        if (ret) {
d1681e
+                                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
d1681e
+                                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                                        "Failed to set dictionary"
d1681e
+                                        "  value:key = %s for "
d1681e
+                                        "path %s", conf->mds_xattr_key,
d1681e
+                                        local->loc.path);
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+
d1681e
+                        xattr_frame = create_frame (this, this->ctx->pool);
d1681e
+                        if (!xattr_frame) {
d1681e
+                                ret = -1;
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+                        copy_local = dht_local_init (xattr_frame, &(local->loc),
d1681e
+                                                     NULL, 0);
d1681e
+                        if (!copy_local) {
d1681e
+                                ret = -1;
d1681e
+                                DHT_STACK_DESTROY (xattr_frame);
d1681e
+                                goto out;
d1681e
+                        }
d1681e
+
d1681e
+                        copy_local->stbuf = local->stbuf;
d1681e
+                        copy_local->inode = inode_ref (local->inode);
d1681e
+                        gf_uuid_copy (copy_local->loc.gfid, local->gfid);
d1681e
+
d1681e
+                        STACK_WIND_COOKIE (xattr_frame,
d1681e
+                                           dht_selfheal_dir_check_set_mdsxattr_cbk,
d1681e
+                                           (void *)hashed_subvol, hashed_subvol,
d1681e
+                                           hashed_subvol->fops->setxattr,
d1681e
+                                           loc, xattrs, 0, NULL);
d1681e
+                        ret = 0;
d1681e
+                }
d1681e
+        } else {
d1681e
+                ret = 0;
d1681e
+                gf_msg_debug (this->name, 0,
d1681e
+                              "internal xattr %s is present on subvol"
d1681e
+                              "on path %s gfid is %s " , conf->mds_xattr_key,
d1681e
+                               local->loc.path, gfid_local);
d1681e
+        }
d1681e
+
d1681e
+out:
d1681e
+        if (xattrs)
d1681e
+                dict_unref (xattrs);
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
 
d1681e
 int
d1681e
 dht_selfheal_dir_setattr (call_frame_t *frame, loc_t *loc, struct iatt *stbuf,
d1681e
@@ -1159,7 +1313,40 @@ dht_selfheal_dir_setattr (call_frame_t *frame, loc_t *loc, struct iatt *stbuf,
d1681e
                         missing_attr++;
d1681e
         }
d1681e
 
d1681e
+        if (!__is_root_gfid (local->stbuf.ia_gfid)) {
d1681e
+                if (local->need_xattr_heal) {
d1681e
+                        local->need_xattr_heal = 0;
d1681e
+                        ret =  dht_dir_xattr_heal (this, local);
d1681e
+                        if (ret)
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR,
d1681e
+                                        ret,
d1681e
+                                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                        "xattr heal failed for "
d1681e
+                                        "directory  %s gfid %s ",
d1681e
+                                        local->loc.path,
d1681e
+                                        local->gfid);
d1681e
+                } else {
d1681e
+                        ret = dht_selfheal_dir_check_set_mdsxattr (frame, loc);
d1681e
+                        if (ret)
d1681e
+                                gf_msg (this->name, GF_LOG_INFO, ret,
d1681e
+                                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                        "set mds internal xattr failed for "
d1681e
+                                        "directory  %s gfid %s ", local->loc.path,
d1681e
+                                        local->gfid);
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
+        if (!gf_uuid_is_null (local->gfid))
d1681e
+                gf_uuid_copy (loc->gfid, local->gfid);
d1681e
+
d1681e
         if (missing_attr == 0) {
d1681e
+                if (!local->heal_layout) {
d1681e
+                        gf_msg_trace (this->name, 0,
d1681e
+                                      "Skip heal layout for %s gfid = %s ",
d1681e
+                                      loc->path, uuid_utoa(loc->gfid));
d1681e
+                        dht_selfheal_dir_finish (frame, this, 0, 1);
d1681e
+                        return 0;
d1681e
+                }
d1681e
                 ret = dht_selfheal_layout_lock (frame, layout, _gf_false,
d1681e
                                                 dht_selfheal_dir_xattr,
d1681e
                                                 dht_should_heal_layout);
d1681e
@@ -1171,11 +1358,9 @@ dht_selfheal_dir_setattr (call_frame_t *frame, loc_t *loc, struct iatt *stbuf,
d1681e
                 return 0;
d1681e
         }
d1681e
 
d1681e
-        if (!gf_uuid_is_null (local->gfid))
d1681e
-                gf_uuid_copy (loc->gfid, local->gfid);
d1681e
-
d1681e
         local->call_cnt = missing_attr;
d1681e
         cnt = layout->cnt;
d1681e
+
d1681e
         for (i = 0; i < cnt; i++) {
d1681e
                 if (layout->list[i].err == -1) {
d1681e
                         gf_msg_trace (this->name, 0,
d1681e
@@ -1291,16 +1476,66 @@ out:
d1681e
         return;
d1681e
 }
d1681e
 
d1681e
+
d1681e
+void
d1681e
+dht_selfheal_dir_mkdir_setquota (dict_t *src, dict_t *dst)
d1681e
+{
d1681e
+        data_t           *quota_limit_key = NULL;
d1681e
+        data_t           *quota_limit_obj_key = NULL;
d1681e
+        xlator_t        *this = NULL;
d1681e
+        int     ret = -1;
d1681e
+
d1681e
+        GF_ASSERT (src);
d1681e
+        GF_ASSERT (dst);
d1681e
+
d1681e
+        this = THIS;
d1681e
+        GF_ASSERT (this);
d1681e
+
d1681e
+        quota_limit_key = dict_get (src, QUOTA_LIMIT_KEY);
d1681e
+        if (!quota_limit_key) {
d1681e
+                gf_msg_debug (this->name, 0,
d1681e
+                              "QUOTA_LIMIT_KEY xattr not present");
d1681e
+                goto cont;
d1681e
+        }
d1681e
+        ret = dict_set(dst, QUOTA_LIMIT_KEY, quota_limit_key);
d1681e
+        if (ret)
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
+                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                        "Failed to set dictionary value.key = %s",
d1681e
+                        QUOTA_LIMIT_KEY);
d1681e
+
d1681e
+cont:
d1681e
+        quota_limit_obj_key = dict_get (src, QUOTA_LIMIT_OBJECTS_KEY);
d1681e
+        if (!quota_limit_obj_key) {
d1681e
+                gf_msg_debug (this->name, 0,
d1681e
+                              "QUOTA_LIMIT_OBJECTS_KEY xattr not present");
d1681e
+                goto out;
d1681e
+        }
d1681e
+        ret = dict_set (dst, QUOTA_LIMIT_OBJECTS_KEY, quota_limit_obj_key);
d1681e
+        if (ret)
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
+                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                        "Failed to set dictionary value.key = %s",
d1681e
+                        QUOTA_LIMIT_OBJECTS_KEY);
d1681e
+
d1681e
+out:
d1681e
+        return;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
+
d1681e
 int
d1681e
 dht_selfheal_dir_mkdir_lookup_done (call_frame_t *frame, xlator_t *this)
d1681e
 {
d1681e
         dht_local_t  *local = NULL;
d1681e
         int           i     = 0;
d1681e
-        int           ret   = -1;
d1681e
         dict_t       *dict = NULL;
d1681e
         dht_layout_t  *layout = NULL;
d1681e
         loc_t        *loc   = NULL;
d1681e
         int           cnt   = 0;
d1681e
+        int          ret    = -1;
d1681e
 
d1681e
         VALIDATE_OR_GOTO (this->private, err);
d1681e
 
d1681e
@@ -1324,9 +1559,11 @@ dht_selfheal_dir_mkdir_lookup_done (call_frame_t *frame, xlator_t *this)
d1681e
 
d1681e
                 dict = dict_ref (local->params);
d1681e
         }
d1681e
-        /* Set acls */
d1681e
-        if (local->xattr && dict)
d1681e
-                dht_selfheal_dir_mkdir_setacl (local->xattr, dict);
d1681e
+        /* Code to update all extended attributed from local->xattr
d1681e
+           to dict
d1681e
+        */
d1681e
+        dht_dir_set_heal_xattr (this, local, dict, local->xattr, NULL,
d1681e
+                                NULL);
d1681e
 
d1681e
         if (!dict)
d1681e
                 gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
@@ -1374,8 +1611,13 @@ dht_selfheal_dir_mkdir_lookup_cbk (call_frame_t *frame, void *cookie,
d1681e
         int           this_call_cnt = 0;
d1681e
         int           missing_dirs = 0;
d1681e
         dht_layout_t  *layout = NULL;
d1681e
+        dht_conf_t    *conf   = 0;
d1681e
         loc_t         *loc    = NULL;
d1681e
         xlator_t      *prev    = NULL;
d1681e
+        int           check_mds = 0;
d1681e
+        int           errst     = 0;
d1681e
+        int32_t       mds_xattr_val[1] = {0};
d1681e
+        char          gfid_local[GF_UUID_BUF_SIZE] = {0};
d1681e
 
d1681e
         VALIDATE_OR_GOTO (this->private, err);
d1681e
 
d1681e
@@ -1383,6 +1625,10 @@ dht_selfheal_dir_mkdir_lookup_cbk (call_frame_t *frame, void *cookie,
d1681e
         layout = local->layout;
d1681e
         loc = &local->loc;
d1681e
         prev  = cookie;
d1681e
+        conf = this->private;
d1681e
+
d1681e
+        if (local->gfid)
d1681e
+                gf_uuid_unparse(local->gfid, gfid_local);
d1681e
 
d1681e
         this_call_cnt = dht_frame_return (frame);
d1681e
 
d1681e
@@ -1397,6 +1643,12 @@ dht_selfheal_dir_mkdir_lookup_cbk (call_frame_t *frame, void *cookie,
d1681e
                 if (!op_ret) {
d1681e
                         dht_iatt_merge (this, &local->stbuf, stbuf, prev);
d1681e
                 }
d1681e
+                check_mds = dht_dict_get_array (xattr, conf->mds_xattr_key,
d1681e
+                                                mds_xattr_val, 1, &errst);
d1681e
+                if (dict_get (xattr, conf->mds_xattr_key) && check_mds && !errst) {
d1681e
+                        dict_unref (local->xattr);
d1681e
+                        local->xattr = dict_ref (xattr);
d1681e
+                }
d1681e
 
d1681e
         }
d1681e
         UNLOCK (&frame->lock);
d1681e
@@ -1445,13 +1697,16 @@ dht_selfheal_dir_mkdir_lock_cbk (call_frame_t *frame, void *cookie,
d1681e
         dht_local_t  *local = NULL;
d1681e
         dht_conf_t   *conf  = NULL;
d1681e
         int           i     = 0;
d1681e
+        int           ret   = -1;
d1681e
+        xlator_t     *mds_subvol = NULL;
d1681e
 
d1681e
         VALIDATE_OR_GOTO (this->private, err);
d1681e
 
d1681e
         conf = this->private;
d1681e
         local = frame->local;
d1681e
+        mds_subvol = local->mds_subvol;
d1681e
 
d1681e
-	    local->call_cnt = conf->subvolume_cnt;
d1681e
+        local->call_cnt = conf->subvolume_cnt;
d1681e
 
d1681e
         if (op_ret < 0) {
d1681e
 
d1681e
@@ -1477,12 +1732,32 @@ dht_selfheal_dir_mkdir_lock_cbk (call_frame_t *frame, void *cookie,
d1681e
         /* After getting locks, perform lookup again to ensure that the
d1681e
            directory was not deleted by a racing rmdir
d1681e
         */
d1681e
+        if (!local->xattr_req)
d1681e
+                local->xattr_req = dict_new ();
d1681e
+
d1681e
+        ret = dict_set_int32 (local->xattr_req, "list-xattr", 1);
d1681e
+        if (ret)
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                        DHT_MSG_DICT_SET_FAILED,
d1681e
+                        "Failed to set dictionary key list-xattr value "
d1681e
+                        " for path %s ", local->loc.path);
d1681e
 
d1681e
         for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
-                STACK_WIND_COOKIE (frame, dht_selfheal_dir_mkdir_lookup_cbk,
d1681e
-                                   conf->subvolumes[i], conf->subvolumes[i],
d1681e
-                                   conf->subvolumes[i]->fops->lookup,
d1681e
-                                   &local->loc, NULL);
d1681e
+                if (mds_subvol && conf->subvolumes[i] == mds_subvol) {
d1681e
+                        STACK_WIND_COOKIE (frame,
d1681e
+                                           dht_selfheal_dir_mkdir_lookup_cbk,
d1681e
+                                           conf->subvolumes[i],
d1681e
+                                           conf->subvolumes[i],
d1681e
+                                           conf->subvolumes[i]->fops->lookup,
d1681e
+                                           &local->loc, local->xattr_req);
d1681e
+                } else {
d1681e
+                       STACK_WIND_COOKIE (frame,
d1681e
+                                          dht_selfheal_dir_mkdir_lookup_cbk,
d1681e
+                                          conf->subvolumes[i],
d1681e
+                                          conf->subvolumes[i],
d1681e
+                                          conf->subvolumes[i]->fops->lookup,
d1681e
+                                          &local->loc, NULL);
d1681e
+                }
d1681e
         }
d1681e
 
d1681e
         return 0;
d1681e
@@ -2171,15 +2446,16 @@ dht_selfheal_directory (call_frame_t *frame, dht_selfheal_dir_cbk_t dir_cbk,
d1681e
         }
d1681e
 
d1681e
         dht_layout_sort_volname (layout);
d1681e
+        local->heal_layout = _gf_true;
d1681e
         ret = dht_selfheal_dir_getafix (frame, loc, layout);
d1681e
 
d1681e
         if (ret == -1) {
d1681e
-                gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
+                gf_msg (this->name, GF_LOG_INFO, 0,
d1681e
                         DHT_MSG_DIR_SELFHEAL_FAILED,
d1681e
                         "Directory selfheal failed: "
d1681e
                         "Unable to form layout for directory %s",
d1681e
                         loc->path);
d1681e
-                goto sorry_no_fix;
d1681e
+                local->heal_layout = _gf_false;
d1681e
         }
d1681e
 
d1681e
         dht_selfheal_dir_mkdir (frame, loc, layout, 0);
d1681e
@@ -2281,23 +2557,196 @@ dht_selfheal_restore (call_frame_t *frame, dht_selfheal_dir_cbk_t dir_cbk,
d1681e
 }
d1681e
 
d1681e
 int
d1681e
+dht_dir_heal_xattrs (void *data)
d1681e
+{
d1681e
+        call_frame_t    *frame          = NULL;
d1681e
+        dht_local_t     *local          = NULL;
d1681e
+        xlator_t        *subvol         = NULL;
d1681e
+        xlator_t        *mds_subvol     = NULL;
d1681e
+        xlator_t        *this           = NULL;
d1681e
+        dht_conf_t      *conf           = NULL;
d1681e
+        dict_t          *user_xattr     = NULL;
d1681e
+        dict_t          *internal_xattr = NULL;
d1681e
+        dict_t          *mds_xattr   = NULL;
d1681e
+        dict_t          *xdata          = NULL;
d1681e
+        int              call_cnt       = 0;
d1681e
+        int              ret            = -1;
d1681e
+        int              uret           = 0;
d1681e
+        int              uflag          = 0;
d1681e
+        int              i              = 0;
d1681e
+        int              xattr_hashed   = 0;
d1681e
+        char     gfid[GF_UUID_BUF_SIZE] = {0};
d1681e
+        int32_t    allzero[1]           = {0};
d1681e
+
d1681e
+        GF_VALIDATE_OR_GOTO ("dht", data, out);
d1681e
+
d1681e
+        frame = data;
d1681e
+        local = frame->local;
d1681e
+        this = frame->this;
d1681e
+        GF_VALIDATE_OR_GOTO ("dht", this, out);
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, local, out);
d1681e
+        mds_subvol = local->mds_subvol;
d1681e
+        conf = this->private;
d1681e
+        GF_VALIDATE_OR_GOTO (this->name, conf, out);
d1681e
+        gf_uuid_unparse(local->loc.gfid, gfid);
d1681e
+
d1681e
+        if (!mds_subvol) {
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
+                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                        "No mds subvol for %s gfid = %s",
d1681e
+                        local->loc.path, gfid);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        if ((local->loc.inode && gf_uuid_is_null (local->loc.inode->gfid)) ||
d1681e
+            gf_uuid_is_null (local->loc.gfid)) {
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
+                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                        "No gfid present so skip heal for path %s gfid = %s",
d1681e
+                        local->loc.path, gfid);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        internal_xattr = dict_new ();
d1681e
+        if (!internal_xattr) {
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, DHT_MSG_NO_MEMORY, 0,
d1681e
+                        "dictionary creation failed");
d1681e
+                goto out;
d1681e
+        }
d1681e
+        xdata = dict_new ();
d1681e
+        if (!xdata) {
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, DHT_MSG_NO_MEMORY, 0,
d1681e
+                        "dictionary creation failed");
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        call_cnt = conf->subvolume_cnt;
d1681e
+
d1681e
+        user_xattr = dict_new ();
d1681e
+        if (!user_xattr) {
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, DHT_MSG_NO_MEMORY, 0,
d1681e
+                        "dictionary creation failed");
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        ret = syncop_listxattr (local->mds_subvol, &local->loc,
d1681e
+                                &mds_xattr, NULL, NULL);
d1681e
+        if (ret < 0) {
d1681e
+                gf_msg (this->name, GF_LOG_ERROR, -ret,
d1681e
+                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                        "failed to list xattrs for "
d1681e
+                        "%s: on %s ",
d1681e
+                        local->loc.path, local->mds_subvol->name);
d1681e
+        }
d1681e
+
d1681e
+        if (!mds_xattr)
d1681e
+                goto out;
d1681e
+
d1681e
+        dht_dir_set_heal_xattr (this, local, user_xattr, mds_xattr,
d1681e
+                                &uret, &uflag);
d1681e
+
d1681e
+        /* To set quota related xattr need to set GLUSTERFS_INTERNAL_FOP_KEY
d1681e
+         * key value to 1
d1681e
+         */
d1681e
+        if (dict_get (user_xattr, QUOTA_LIMIT_KEY) ||
d1681e
+            dict_get (user_xattr, QUOTA_LIMIT_OBJECTS_KEY)) {
d1681e
+                ret = dict_set_int32 (xdata, GLUSTERFS_INTERNAL_FOP_KEY, 1);
d1681e
+                if (ret) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
d1681e
+                                DHT_MSG_DICT_SET_FAILED,
d1681e
+                                "Failed to set dictionary value: key = %s,"
d1681e
+                                " path = %s", GLUSTERFS_INTERNAL_FOP_KEY,
d1681e
+                                 local->loc.path);
d1681e
+                        goto out;
d1681e
+                }
d1681e
+        }
d1681e
+        if (uret <= 0 && !uflag)
d1681e
+                goto out;
d1681e
+
d1681e
+        for (i = 0; i < call_cnt; i++) {
d1681e
+                subvol = conf->subvolumes[i];
d1681e
+                if (subvol == mds_subvol)
d1681e
+                        continue;
d1681e
+                if (uret || uflag) {
d1681e
+                        ret = syncop_setxattr (subvol, &local->loc, user_xattr,
d1681e
+                                               0, xdata, NULL);
d1681e
+                        if (ret) {
d1681e
+                                xattr_hashed = 1;
d1681e
+                                gf_msg (this->name, GF_LOG_ERROR, -ret,
d1681e
+                                        DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                        "Directory xattr heal failed. Failed to set"
d1681e
+                                        "user xattr on path %s on "
d1681e
+                                        "subvol %s, gfid = %s ",
d1681e
+                                        local->loc.path, subvol->name, gfid);
d1681e
+                        }
d1681e
+                }
d1681e
+        }
d1681e
+        /* After heal all custom xattr reset internal MDS xattr to 0 */
d1681e
+        if (!xattr_hashed) {
d1681e
+                ret = dht_dict_set_array (internal_xattr,
d1681e
+                                          conf->mds_xattr_key,
d1681e
+                                          allzero, 1);
d1681e
+                if (ret) {
d1681e
+                        gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
d1681e
+                                DHT_MSG_DICT_SET_FAILED,
d1681e
+                                "Failed to set dictionary value:key = %s for "
d1681e
+                                "path %s", conf->mds_xattr_key,
d1681e
+                                local->loc.path);
d1681e
+                        goto out;
d1681e
+                }
d1681e
+                ret = syncop_setxattr (mds_subvol, &local->loc, internal_xattr,
d1681e
+                                       0, NULL, NULL);
d1681e
+                if (ret) {
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, -ret,
d1681e
+                                DHT_MSG_DIR_XATTR_HEAL_FAILED,
d1681e
+                                "Failed to reset internal xattr "
d1681e
+                                "on path %s on subvol %s"
d1681e
+                                "gfid = %s ", local->loc.path,
d1681e
+                                mds_subvol->name, gfid);
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
+out:
d1681e
+        if (user_xattr)
d1681e
+                dict_unref (user_xattr);
d1681e
+        if (mds_xattr)
d1681e
+                dict_unref (mds_xattr);
d1681e
+        if (internal_xattr)
d1681e
+                dict_unref (internal_xattr);
d1681e
+        if (xdata)
d1681e
+                dict_unref (xdata);
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+int
d1681e
+dht_dir_heal_xattrs_done (int ret, call_frame_t *sync_frame, void *data)
d1681e
+{
d1681e
+        DHT_STACK_DESTROY (sync_frame);
d1681e
+        return 0;
d1681e
+}
d1681e
+
d1681e
+
d1681e
+int
d1681e
 dht_dir_attr_heal (void *data)
d1681e
 {
d1681e
-        call_frame_t    *frame = NULL;
d1681e
-        dht_local_t     *local = NULL;
d1681e
-        xlator_t        *subvol = NULL;
d1681e
-        xlator_t        *this  = NULL;
d1681e
+        call_frame_t    *frame      = NULL;
d1681e
+        dht_local_t     *local      = NULL;
d1681e
+        xlator_t        *subvol     = NULL;
d1681e
+        xlator_t        *mds_subvol = NULL;
d1681e
+        xlator_t        *this       = NULL;
d1681e
         dht_conf_t      *conf  = NULL;
d1681e
         int              call_cnt = 0;
d1681e
         int              ret   = -1;
d1681e
         int              i     = 0;
d1681e
-        char         gfid[GF_UUID_BUF_SIZE] = {0};
d1681e
+        char             gfid[GF_UUID_BUF_SIZE] = {0};
d1681e
 
d1681e
 
d1681e
         GF_VALIDATE_OR_GOTO ("dht", data, out);
d1681e
 
d1681e
         frame = data;
d1681e
         local = frame->local;
d1681e
+        mds_subvol = local->mds_subvol;
d1681e
         this = frame->this;
d1681e
         GF_VALIDATE_OR_GOTO ("dht", this, out);
d1681e
         GF_VALIDATE_OR_GOTO ("dht", local, out);
d1681e
@@ -2306,17 +2755,39 @@ dht_dir_attr_heal (void *data)
d1681e
 
d1681e
         call_cnt = conf->subvolume_cnt;
d1681e
 
d1681e
+        if (!__is_root_gfid (local->stbuf.ia_gfid) && (!mds_subvol)) {
d1681e
+                gf_msg (this->name, GF_LOG_WARNING, 0,
d1681e
+                        DHT_MSG_DIR_ATTR_HEAL_FAILED,
d1681e
+                        "No mds subvol for %s gfid = %s",
d1681e
+                        local->loc.path, gfid);
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        if (!__is_root_gfid (local->stbuf.ia_gfid)) {
d1681e
+                for (i = 0; i < conf->subvolume_cnt; i++) {
d1681e
+                        if (conf->subvolumes[i] ==  mds_subvol) {
d1681e
+                                if (!conf->subvolume_status[i]) {
d1681e
+                                        gf_msg (this->name, GF_LOG_ERROR,
d1681e
+                                                0,  DHT_MSG_HASHED_SUBVOL_DOWN,
d1681e
+                                                "mds subvol is down for path "
d1681e
+                                                " %s gfid is %s Unable to set xattr " ,
d1681e
+                                                local->loc.path, gfid);
d1681e
+                                        goto out;
d1681e
+                                }
d1681e
+                        }
d1681e
+                }
d1681e
+        }
d1681e
+
d1681e
         for (i = 0; i < call_cnt; i++) {
d1681e
                 subvol = conf->subvolumes[i];
d1681e
-                if (!subvol)
d1681e
+                if (!subvol || subvol == mds_subvol)
d1681e
                         continue;
d1681e
-
d1681e
                 if (__is_root_gfid (local->stbuf.ia_gfid)) {
d1681e
                         ret = syncop_setattr (subvol, &local->loc, &local->stbuf,
d1681e
                                               (GF_SET_ATTR_UID | GF_SET_ATTR_GID | GF_SET_ATTR_MODE),
d1681e
                                               NULL, NULL, NULL, NULL);
d1681e
                 } else {
d1681e
-                        ret = syncop_setattr (subvol, &local->loc, &local->stbuf,
d1681e
+                        ret = syncop_setattr (subvol, &local->loc, &local->mds_stbuf,
d1681e
                                               (GF_SET_ATTR_UID | GF_SET_ATTR_GID),
d1681e
                                               NULL, NULL, NULL, NULL);
d1681e
                 }
d1681e
@@ -2324,7 +2795,7 @@ dht_dir_attr_heal (void *data)
d1681e
                 if (ret) {
d1681e
                         gf_uuid_unparse(local->loc.gfid, gfid);
d1681e
 
d1681e
-                        gf_msg ("dht", GF_LOG_ERROR, -ret,
d1681e
+                        gf_msg (this->name, GF_LOG_ERROR, -ret,
d1681e
                                 DHT_MSG_DIR_ATTR_HEAL_FAILED,
d1681e
                                 "Directory attr heal failed. Failed to set"
d1681e
                                 " uid/gid on path %s on subvol %s, gfid = %s ",
d1681e
diff --git a/xlators/cluster/dht/src/dht-shared.c b/xlators/cluster/dht/src/dht-shared.c
d1681e
index 0373ebf..42daff0 100644
d1681e
--- a/xlators/cluster/dht/src/dht-shared.c
d1681e
+++ b/xlators/cluster/dht/src/dht-shared.c
d1681e
@@ -868,6 +868,7 @@ dht_init (xlator_t *this)
d1681e
         }
d1681e
 
d1681e
         GF_OPTION_INIT ("xattr-name", conf->xattr_name, str, err);
d1681e
+        gf_asprintf (&conf->mds_xattr_key, "%s."DHT_MDS_STR, conf->xattr_name);
d1681e
         gf_asprintf (&conf->link_xattr_name, "%s."DHT_LINKFILE_STR,
d1681e
                      conf->xattr_name);
d1681e
         gf_asprintf (&conf->commithash_xattr_name, "%s."DHT_COMMITHASH_STR,
d1681e
@@ -917,6 +918,7 @@ err:
d1681e
                 GF_FREE (conf->xattr_name);
d1681e
                 GF_FREE (conf->link_xattr_name);
d1681e
                 GF_FREE (conf->wild_xattr_name);
d1681e
+                GF_FREE (conf->mds_xattr_key);
d1681e
 
d1681e
                 if (conf->lock_pool)
d1681e
                         mem_pool_destroy (conf->lock_pool);
d1681e
-- 
d1681e
1.8.3.1
d1681e