d2787b
From aab8a587360214432c4a2ab59134411f1d38c509 Mon Sep 17 00:00:00 2001
d2787b
From: karthik-us <ksubrahm@redhat.com>
d2787b
Date: Wed, 9 Dec 2020 10:46:31 +0530
d2787b
Subject: [PATCH 515/517] cluster/afr: Heal directory rename without
d2787b
 rmdir/mkdir
d2787b
d2787b
Problem1:
d2787b
When a directory is renamed while a brick
d2787b
is down entry-heal always did an rm -rf on that directory on
d2787b
the sink on old location and did mkdir and created the directory
d2787b
hierarchy again in the new location. This is inefficient.
d2787b
d2787b
Problem2:
d2787b
Renamedir heal order may lead to a scenario where directory in
d2787b
the new location could be created before deleting it from old
d2787b
location leading to 2 directories with same gfid in posix.
d2787b
d2787b
Fix:
d2787b
As part of heal, if oldlocation is healed first and is not present in
d2787b
source-brick always rename it into a hidden directory inside the
d2787b
sink-brick so that when heal is triggered in new-location shd can
d2787b
rename it from this hidden directory to the new-location.
d2787b
d2787b
If new-location heal is triggered first and it detects that the
d2787b
directory already exists in the brick, then it should skip healing the
d2787b
directory until it appears in the hidden directory.
d2787b
d2787b
Credits: Ravi for rename-data-loss.t script
d2787b
d2787b
Upstream patch details:
d2787b
> Fixes: #1211
d2787b
> Change-Id: I0cba2006f35cd03d314d18211ce0bd530e254843
d2787b
> Signed-off-by: Pranith Kumar K <pkarampu@redhat.com>
d2787b
Upstream patch: https://review.gluster.org/#/c/glusterfs/+/24373/
d2787b
d2787b
BUG: 1640148
d2787b
Change-Id: I0cba2006f35cd03d314d18211ce0bd530e254843
d2787b
Signed-off-by: karthik-us <ksubrahm@redhat.com>
d2787b
Reviewed-on: https://code.engineering.redhat.com/gerrit/220660
d2787b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d2787b
Reviewed-by: Ravishankar Narayanankutty <ravishankar@redhat.com>
d2787b
---
d2787b
 tests/afr.rc                                    |  16 +
d2787b
 tests/basic/afr/afr-anon-inode-no-quorum.t      |  63 ++++
d2787b
 tests/basic/afr/afr-anon-inode.t                | 114 ++++++
d2787b
 tests/basic/afr/entry-self-heal-anon-dir-off.t  | 464 ++++++++++++++++++++++++
d2787b
 tests/basic/afr/rename-data-loss.t              |  72 ++++
d2787b
 tests/bugs/replicate/bug-1744548-heal-timeout.t |   6 +-
d2787b
 tests/features/trash.t                          |  74 ++--
d2787b
 xlators/cluster/afr/src/afr-common.c            |  46 ++-
d2787b
 xlators/cluster/afr/src/afr-dir-read.c          |  12 +-
d2787b
 xlators/cluster/afr/src/afr-self-heal-common.c  | 182 ++++++++++
d2787b
 xlators/cluster/afr/src/afr-self-heal-entry.c   | 206 +++++++++--
d2787b
 xlators/cluster/afr/src/afr-self-heal-name.c    |  33 +-
d2787b
 xlators/cluster/afr/src/afr-self-heal.h         |   5 +
d2787b
 xlators/cluster/afr/src/afr-self-heald.c        | 178 ++++++++-
d2787b
 xlators/cluster/afr/src/afr-self-heald.h        |   2 +-
d2787b
 xlators/cluster/afr/src/afr.c                   |  40 +-
d2787b
 xlators/cluster/afr/src/afr.h                   |  11 +
d2787b
 xlators/mgmt/glusterd/src/glusterd-volgen.c     |  39 ++
d2787b
 xlators/mgmt/glusterd/src/glusterd-volume-set.c |   6 +
d2787b
 19 files changed, 1442 insertions(+), 127 deletions(-)
d2787b
 create mode 100644 tests/basic/afr/afr-anon-inode-no-quorum.t
d2787b
 create mode 100644 tests/basic/afr/afr-anon-inode.t
d2787b
 create mode 100644 tests/basic/afr/entry-self-heal-anon-dir-off.t
d2787b
 create mode 100644 tests/basic/afr/rename-data-loss.t
d2787b
d2787b
diff --git a/tests/afr.rc b/tests/afr.rc
d2787b
index 35f352d..2417899 100644
d2787b
--- a/tests/afr.rc
d2787b
+++ b/tests/afr.rc
d2787b
@@ -105,3 +105,19 @@ function get_quorum_type()
d2787b
         local repl_id="$3"
d2787b
         cat $m/.meta/graphs/active/$v-replicate-$repl_id/private|grep quorum-type|awk '{print $3}'
d2787b
 }
d2787b
+
d2787b
+function afr_private_key_value()
d2787b
+{
d2787b
+        local v=$1
d2787b
+        local m=$2
d2787b
+        local replica_id=$3
d2787b
+        local key=$4
d2787b
+#xargs at the end will strip leading spaces
d2787b
+        grep -E "^${key} = " $m/.meta/graphs/active/${v}-replicate-${replica_id}/private | cut -f2 -d'=' | xargs
d2787b
+}
d2787b
+
d2787b
+function afr_anon_entry_count()
d2787b
+{
d2787b
+    local b=$1
d2787b
+    ls $b/.glusterfs-anonymous-inode* | wc -l
d2787b
+}
d2787b
diff --git a/tests/basic/afr/afr-anon-inode-no-quorum.t b/tests/basic/afr/afr-anon-inode-no-quorum.t
d2787b
new file mode 100644
d2787b
index 0000000..896ba0c
d2787b
--- /dev/null
d2787b
+++ b/tests/basic/afr/afr-anon-inode-no-quorum.t
d2787b
@@ -0,0 +1,63 @@
d2787b
+#!/bin/bash
d2787b
+
d2787b
+#Test that anon-inode entry is not cleaned up as long as there exists at least
d2787b
+#one valid entry
d2787b
+. $(dirname $0)/../../include.rc
d2787b
+. $(dirname $0)/../../volume.rc
d2787b
+. $(dirname $0)/../../afr.rc
d2787b
+
d2787b
+cleanup;
d2787b
+
d2787b
+TEST glusterd
d2787b
+TEST pidof glusterd
d2787b
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
d2787b
+TEST $CLI volume heal $V0 disable
d2787b
+TEST $CLI volume set $V0 performance.write-behind off
d2787b
+TEST $CLI volume set $V0 performance.read-ahead off
d2787b
+TEST $CLI volume set $V0 performance.readdir-ahead off
d2787b
+TEST $CLI volume set $V0 performance.open-behind off
d2787b
+TEST $CLI volume set $V0 performance.stat-prefetch off
d2787b
+TEST $CLI volume set $V0 performance.io-cache off
d2787b
+TEST $CLI volume set $V0 performance.quick-read off
d2787b
+TEST $CLI volume set $V0 cluster.entry-self-heal off
d2787b
+TEST $CLI volume start $V0
d2787b
+
d2787b
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0
d2787b
+
d2787b
+TEST touch $M0/a $M0/b
d2787b
+
d2787b
+gfid_a=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/a))
d2787b
+gfid_b=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/b))
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}0
d2787b
+TEST mv $M0/a $M0/a-new
d2787b
+TEST mv $M0/b $M0/b-new
d2787b
+
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+TEST ! ls $M0/a
d2787b
+TEST ! ls $M0/b
d2787b
+anon_inode_name=$(ls -a $B0/${V0}0 | grep glusterfs-anonymous-inode)
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$gfid_a
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$gfid_b
d2787b
+#Make sure index heal doesn't happen after enabling heal
d2787b
+TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1
d2787b
+TEST rm -f $B0/${V0}1/.glusterfs/indices/xattrop/*
d2787b
+TEST $CLI volume heal $V0 enable
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
d2787b
+TEST $CLI volume heal $V0
d2787b
+#Allow time for a scan
d2787b
+sleep 5
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$gfid_a
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$gfid_b
d2787b
+inum_b=$(STAT_INO $B0/${V0}0/$anon_inode_name/$gfid_b)
d2787b
+TEST rm -f $M0/a-new
d2787b
+TEST stat $M0/b-new
d2787b
+
d2787b
+TEST $CLI volume heal $V0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}1
d2787b
+EXPECT "$inum_b" STAT_INO $B0/${V0}0/b-new
d2787b
+
d2787b
+cleanup
d2787b
diff --git a/tests/basic/afr/afr-anon-inode.t b/tests/basic/afr/afr-anon-inode.t
d2787b
new file mode 100644
d2787b
index 0000000..f4cf37a
d2787b
--- /dev/null
d2787b
+++ b/tests/basic/afr/afr-anon-inode.t
d2787b
@@ -0,0 +1,114 @@
d2787b
+#!/bin/bash
d2787b
+#Tests that afr-anon-inode test cases work fine as expected
d2787b
+#These are cases where in entry-heal/name-heal we dont know entry for an inode
d2787b
+#so these inodes are kept in a special directory
d2787b
+
d2787b
+. $(dirname $0)/../../include.rc
d2787b
+. $(dirname $0)/../../volume.rc
d2787b
+. $(dirname $0)/../../afr.rc
d2787b
+
d2787b
+cleanup;
d2787b
+
d2787b
+TEST glusterd
d2787b
+TEST pidof glusterd
d2787b
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0..2}
d2787b
+TEST $CLI volume set $V0 performance.quick-read off
d2787b
+TEST $CLI volume set $V0 performance.io-cache off
d2787b
+TEST $CLI volume set $V0 performance.write-behind off
d2787b
+TEST $CLI volume set $V0 performance.stat-prefetch off
d2787b
+TEST $CLI volume set $V0 performance.read-ahead off
d2787b
+TEST $CLI volume set $V0 performance.open-behind off
d2787b
+TEST $CLI volume start $V0
d2787b
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0;
d2787b
+EXPECT "^1$" afr_private_key_value $V0 $M0 0 "use-anonymous-inode"
d2787b
+TEST $CLI volume set $V0 cluster.use-anonymous-inode no
d2787b
+EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^0$" afr_private_key_value $V0 $M0 0 "use-anonymous-inode"
d2787b
+TEST $CLI volume set $V0 cluster.use-anonymous-inode yes
d2787b
+EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "use-anonymous-inode"
d2787b
+TEST mkdir -p $M0/d1/b $M0/d2/a
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}0
d2787b
+TEST mv $M0/d2/a $M0/d1
d2787b
+TEST mv $M0/d1/b $M0/d2
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0
d2787b
+anon_inode_name=$(ls -a $B0/${V0}0 | grep glusterfs-anonymous-inode)
d2787b
+TEST [[ -d $B0/${V0}1/$anon_inode_name ]]
d2787b
+TEST [[ -d $B0/${V0}2/$anon_inode_name ]]
d2787b
+anon_gfid=$(gf_get_gfid_xattr $B0/${V0}0/$anon_inode_name)
d2787b
+EXPECT "$anon_gfid" gf_get_gfid_xattr $B0/${V0}1/$anon_inode_name
d2787b
+EXPECT "$anon_gfid" gf_get_gfid_xattr $B0/${V0}2/$anon_inode_name
d2787b
+
d2787b
+TEST ! ls $M0/$anon_inode_name
d2787b
+EXPECT "^4$" echo $(ls -a $M0 | wc -l)
d2787b
+
d2787b
+#Test purging code path by shd
d2787b
+TEST $CLI volume heal $V0 disable
d2787b
+TEST mkdir $M0/l0 $M0/l1 $M0/l2
d2787b
+TEST touch $M0/del-file $M0/del-file-nolink $M0/l0/file
d2787b
+TEST ln $M0/del-file $M0/del-file-link
d2787b
+TEST ln $M0/l0/file $M0/l1/file-link1
d2787b
+TEST ln $M0/l0/file $M0/l2/file-link2
d2787b
+TEST mkdir -p $M0/del-recursive-dir/d1
d2787b
+
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}0
d2787b
+TEST rm -f $M0/del-file $M0/del-file-nolink
d2787b
+TEST rm -rf $M0/del-recursive-dir
d2787b
+TEST mv $M0/d1/a $M0/d2
d2787b
+TEST mv $M0/l0/file $M0/l0/renamed-file
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 0
d2787b
+
d2787b
+nolink_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/del-file-nolink))
d2787b
+link_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/del-file))
d2787b
+dir_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/del-recursive-dir))
d2787b
+rename_dir_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/d1/a))
d2787b
+rename_file_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/l0/file))
d2787b
+TEST ! stat $M0/del-file
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$link_gfid
d2787b
+TEST ! stat $M0/del-file-nolink
d2787b
+TEST ! stat $B0/${V0}0/$anon_inode_name/$nolink_gfid
d2787b
+TEST ! stat $M0/del-recursive-dir
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$dir_gfid
d2787b
+TEST ! stat $M0/d1/a
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$rename_dir_gfid
d2787b
+TEST ! stat $M0/l0/file
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$rename_file_gfid
d2787b
+
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}1
d2787b
+TEST mv $M0/l1/file-link1 $M0/l1/renamed-file-link1
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 1
d2787b
+TEST ! stat $M0/l1/file-link1
d2787b
+TEST stat $B0/${V0}1/$anon_inode_name/$rename_file_gfid
d2787b
+
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}2
d2787b
+TEST mv $M0/l2/file-link2 $M0/l2/renamed-file-link2
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 2
d2787b
+TEST ! stat $M0/l2/file-link2
d2787b
+TEST stat $B0/${V0}2/$anon_inode_name/$rename_file_gfid
d2787b
+
d2787b
+#Simulate only anon-inodes present in all bricks
d2787b
+TEST rm -f $M0/l0/renamed-file $M0/l1/renamed-file-link1 $M0/l2/renamed-file-link2
d2787b
+
d2787b
+#Test that shd doesn't cleanup anon-inodes when some bricks are down
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}1
d2787b
+TEST $CLI volume heal $V0 enable
d2787b
+$CLI volume heal $V0
d2787b
+sleep 5 #Allow time for completion of one scan
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$link_gfid
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$rename_dir_gfid
d2787b
+TEST stat $B0/${V0}0/$anon_inode_name/$dir_gfid
d2787b
+rename_dir_inum=$(STAT_INO $B0/${V0}0/$anon_inode_name/$rename_dir_gfid)
d2787b
+
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 1
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}1
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}2
d2787b
+
d2787b
+#Test that rename indeed happened instead of rmdir/mkdir
d2787b
+renamed_dir_inum=$(STAT_INO $B0/${V0}0/d2/a)
d2787b
+EXPECT "$rename_dir_inum" echo $renamed_dir_inum
d2787b
+cleanup;
d2787b
diff --git a/tests/basic/afr/entry-self-heal-anon-dir-off.t b/tests/basic/afr/entry-self-heal-anon-dir-off.t
d2787b
new file mode 100644
d2787b
index 0000000..0803a08
d2787b
--- /dev/null
d2787b
+++ b/tests/basic/afr/entry-self-heal-anon-dir-off.t
d2787b
@@ -0,0 +1,464 @@
d2787b
+#!/bin/bash
d2787b
+
d2787b
+#This file checks if missing entry self-heal and entry self-heal are working
d2787b
+#as expected.
d2787b
+. $(dirname $0)/../../include.rc
d2787b
+. $(dirname $0)/../../volume.rc
d2787b
+. $(dirname $0)/../../afr.rc
d2787b
+
d2787b
+cleanup;
d2787b
+
d2787b
+function get_file_type {
d2787b
+        stat -c "%a:%F:%g:%t:%T:%u" $1
d2787b
+}
d2787b
+
d2787b
+function diff_dirs {
d2787b
+        diff <(ls $1 | sort) <(ls $2 | sort)
d2787b
+}
d2787b
+
d2787b
+function heal_status {
d2787b
+        local f1_path="${1}/${3}"
d2787b
+        local f2_path="${2}/${3}"
d2787b
+        local insync=""
d2787b
+        diff_dirs $f1_path $f2_path
d2787b
+        if [ $? -eq 0 ];
d2787b
+        then
d2787b
+                insync="Y"
d2787b
+        else
d2787b
+                insync="N"
d2787b
+        fi
d2787b
+        local xattr11=$(get_hex_xattr trusted.afr.$V0-client-0 $f1_path)
d2787b
+        local xattr12=$(get_hex_xattr trusted.afr.$V0-client-1 $f1_path)
d2787b
+        local xattr21=$(get_hex_xattr trusted.afr.$V0-client-0 $f2_path)
d2787b
+        local xattr22=$(get_hex_xattr trusted.afr.$V0-client-1 $f2_path)
d2787b
+        local dirty1=$(get_hex_xattr trusted.afr.dirty $f1_path)
d2787b
+        local dirty2=$(get_hex_xattr trusted.afr.dirty $f2_path)
d2787b
+        if [ -z $xattr11 ]; then xattr11="000000000000000000000000"; fi
d2787b
+        if [ -z $xattr12 ]; then xattr12="000000000000000000000000"; fi
d2787b
+        if [ -z $xattr21 ]; then xattr21="000000000000000000000000"; fi
d2787b
+        if [ -z $xattr22 ]; then xattr22="000000000000000000000000"; fi
d2787b
+        if [ -z $dirty1 ]; then dirty1="000000000000000000000000"; fi
d2787b
+        if [ -z $dirty2 ]; then dirty2="000000000000000000000000"; fi
d2787b
+        echo ${insync}${xattr11}${xattr12}${xattr21}${xattr22}${dirty1}${dirty2}
d2787b
+}
d2787b
+
d2787b
+function is_heal_done {
d2787b
+        local zero_xattr="000000000000000000000000"
d2787b
+        if [ "$(heal_status $@)" == "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" ];
d2787b
+        then
d2787b
+                echo "Y"
d2787b
+        else
d2787b
+                echo "N"
d2787b
+        fi
d2787b
+}
d2787b
+
d2787b
+function print_pending_heals {
d2787b
+        local result=":"
d2787b
+        for i in "$@";
d2787b
+        do
d2787b
+                if [ "N" == $(is_heal_done $B0/${V0}0 $B0/${V0}1 $i) ];
d2787b
+                then
d2787b
+                        result="$result:$i"
d2787b
+                fi
d2787b
+        done
d2787b
+#To prevent any match for EXPECT_WITHIN, print a char non-existent in file-names
d2787b
+        if [ $result == ":" ]; then result="~"; fi
d2787b
+        echo $result
d2787b
+}
d2787b
+
d2787b
+zero_xattr="000000000000000000000000"
d2787b
+TEST glusterd
d2787b
+TEST pidof glusterd
d2787b
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
d2787b
+TEST $CLI volume heal $V0 disable
d2787b
+TEST $CLI volume set $V0 cluster.use-anonymous-inode off
d2787b
+TEST $CLI volume set $V0 performance.write-behind off
d2787b
+TEST $CLI volume set $V0 performance.read-ahead off
d2787b
+TEST $CLI volume set $V0 performance.readdir-ahead off
d2787b
+TEST $CLI volume set $V0 performance.open-behind off
d2787b
+TEST $CLI volume set $V0 performance.stat-prefetch off
d2787b
+TEST $CLI volume set $V0 performance.io-cache off
d2787b
+TEST $CLI volume set $V0 performance.quick-read off
d2787b
+TEST $CLI volume set $V0 cluster.data-self-heal on
d2787b
+TEST $CLI volume set $V0 cluster.metadata-self-heal on
d2787b
+TEST $CLI volume set $V0 cluster.entry-self-heal on
d2787b
+TEST $CLI volume start $V0
d2787b
+
d2787b
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --use-readdirp=no $M0
d2787b
+cd $M0
d2787b
+#_me_ is dir on which missing entry self-heal happens, _heal is where dir self-heal happens
d2787b
+#spb is split-brain, fool is all fool
d2787b
+
d2787b
+#source_self_accusing means there exists source and a sink which self-accuses.
d2787b
+#This simulates failures where fops failed on the bricks without it going down.
d2787b
+#Something like EACCESS/EDQUOT etc
d2787b
+
d2787b
+TEST mkdir spb_heal spb spb_me_heal spb_me fool_heal fool_me v1_fool_heal v1_fool_me source_creations_heal source_deletions_heal source_creations_me source_deletions_me v1_dirty_me v1_dirty_heal source_self_accusing
d2787b
+TEST mkfifo source_deletions_heal/fifo
d2787b
+TEST mknod  source_deletions_heal/block b 4 5
d2787b
+TEST mknod  source_deletions_heal/char c 1 5
d2787b
+TEST touch  source_deletions_heal/file
d2787b
+TEST ln -s  source_deletions_heal/file source_deletions_heal/slink
d2787b
+TEST mkdir  source_deletions_heal/dir1
d2787b
+TEST mkdir  source_deletions_heal/dir1/dir2
d2787b
+
d2787b
+TEST mkfifo source_deletions_me/fifo
d2787b
+TEST mknod  source_deletions_me/block b 4 5
d2787b
+TEST mknod  source_deletions_me/char c 1 5
d2787b
+TEST touch  source_deletions_me/file
d2787b
+TEST ln -s  source_deletions_me/file source_deletions_me/slink
d2787b
+TEST mkdir  source_deletions_me/dir1
d2787b
+TEST mkdir  source_deletions_me/dir1/dir2
d2787b
+
d2787b
+TEST mkfifo source_self_accusing/fifo
d2787b
+TEST mknod  source_self_accusing/block b 4 5
d2787b
+TEST mknod  source_self_accusing/char c 1 5
d2787b
+TEST touch  source_self_accusing/file
d2787b
+TEST ln -s  source_self_accusing/file source_self_accusing/slink
d2787b
+TEST mkdir  source_self_accusing/dir1
d2787b
+TEST mkdir  source_self_accusing/dir1/dir2
d2787b
+
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}0
d2787b
+
d2787b
+TEST touch spb_heal/0 spb/0 spb_me_heal/0 spb_me/0 fool_heal/0 fool_me/0 v1_fool_heal/0 v1_fool_me/0 v1_dirty_heal/0 v1_dirty_me/0
d2787b
+TEST rm -rf source_deletions_heal/fifo source_deletions_heal/block source_deletions_heal/char source_deletions_heal/file source_deletions_heal/slink source_deletions_heal/dir1
d2787b
+TEST rm -rf source_deletions_me/fifo source_deletions_me/block source_deletions_me/char source_deletions_me/file source_deletions_me/slink source_deletions_me/dir1
d2787b
+TEST rm -rf source_self_accusing/fifo source_self_accusing/block source_self_accusing/char source_self_accusing/file source_self_accusing/slink source_self_accusing/dir1
d2787b
+
d2787b
+#Test that the files are deleted
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/fifo
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/block
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/char
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/file
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/slink
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/dir1
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/fifo
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/block
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/char
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/file
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/slink
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/dir1
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/fifo
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/block
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/char
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/file
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/slink
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/dir1
d2787b
+
d2787b
+
d2787b
+TEST mkfifo source_creations_heal/fifo
d2787b
+TEST mknod  source_creations_heal/block b 4 5
d2787b
+TEST mknod  source_creations_heal/char c 1 5
d2787b
+TEST touch  source_creations_heal/file
d2787b
+TEST ln -s  source_creations_heal/file source_creations_heal/slink
d2787b
+TEST mkdir  source_creations_heal/dir1
d2787b
+TEST mkdir  source_creations_heal/dir1/dir2
d2787b
+
d2787b
+TEST mkfifo source_creations_me/fifo
d2787b
+TEST mknod  source_creations_me/block b 4 5
d2787b
+TEST mknod  source_creations_me/char c 1 5
d2787b
+TEST touch  source_creations_me/file
d2787b
+TEST ln -s  source_creations_me/file source_creations_me/slink
d2787b
+TEST mkdir  source_creations_me/dir1
d2787b
+TEST mkdir  source_creations_me/dir1/dir2
d2787b
+
d2787b
+$CLI volume stop $V0
d2787b
+
d2787b
+#simulate fool fool scenario for fool_* dirs
d2787b
+setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1/{fool_heal,fool_me}
d2787b
+setfattr -n trusted.afr.dirty -v 0x000000000000000000000001 $B0/${V0}1/{fool_heal,fool_me}
d2787b
+setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}1/{v1_fool_heal,v1_fool_me}
d2787b
+
d2787b
+#Simulate v1-dirty(self-accusing but no pending ops on others) scenario for v1-dirty
d2787b
+setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1/v1_dirty_{heal,me}
d2787b
+setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}1/v1_dirty_{heal,me}
d2787b
+
d2787b
+$CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}1
d2787b
+
d2787b
+TEST touch spb_heal/1 spb/0 spb_me_heal/1 spb_me/0 fool_heal/1 fool_me/1 v1_fool_heal/1 v1_fool_me/1
d2787b
+
d2787b
+$CLI volume stop $V0
d2787b
+
d2787b
+#simulate fool fool scenario for fool_* dirs
d2787b
+setfattr -x trusted.afr.$V0-client-1 $B0/${V0}0/{fool_heal,fool_me}
d2787b
+setfattr -n trusted.afr.dirty -v 0x000000000000000000000001 $B0/${V0}1/{fool_heal,fool_me}
d2787b
+setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}1/{v1_fool_heal,v1_fool_me}
d2787b
+
d2787b
+#simulate self-accusing for source_self_accusing
d2787b
+TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000006 $B0/${V0}0/source_self_accusing
d2787b
+
d2787b
+$CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+
d2787b
+# Check if conservative merges happened correctly on _me_ dirs
d2787b
+TEST stat spb_me_heal/1
d2787b
+TEST stat $B0/${V0}0/spb_me_heal/1
d2787b
+TEST stat $B0/${V0}1/spb_me_heal/1
d2787b
+
d2787b
+TEST stat spb_me_heal/0
d2787b
+TEST stat $B0/${V0}0/spb_me_heal/0
d2787b
+TEST stat $B0/${V0}1/spb_me_heal/0
d2787b
+
d2787b
+TEST stat fool_me/1
d2787b
+TEST stat $B0/${V0}0/fool_me/1
d2787b
+TEST stat $B0/${V0}1/fool_me/1
d2787b
+
d2787b
+TEST stat fool_me/0
d2787b
+TEST stat $B0/${V0}0/fool_me/0
d2787b
+TEST stat $B0/${V0}1/fool_me/0
d2787b
+
d2787b
+TEST stat v1_fool_me/0
d2787b
+TEST stat $B0/${V0}0/v1_fool_me/0
d2787b
+TEST stat $B0/${V0}1/v1_fool_me/0
d2787b
+
d2787b
+TEST stat v1_fool_me/1
d2787b
+TEST stat $B0/${V0}0/v1_fool_me/1
d2787b
+TEST stat $B0/${V0}1/v1_fool_me/1
d2787b
+
d2787b
+TEST stat v1_dirty_me/0
d2787b
+TEST stat $B0/${V0}0/v1_dirty_me/0
d2787b
+TEST stat $B0/${V0}1/v1_dirty_me/0
d2787b
+
d2787b
+#Check if files that have gfid-mismatches in _me_ are giving EIO
d2787b
+TEST ! stat spb_me/0
d2787b
+
d2787b
+#Check if stale files are deleted on access
d2787b
+TEST ! stat source_deletions_me/fifo
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/fifo
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/fifo
d2787b
+TEST ! stat source_deletions_me/block
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/block
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/block
d2787b
+TEST ! stat source_deletions_me/char
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/char
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/char
d2787b
+TEST ! stat source_deletions_me/file
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/file
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/file
d2787b
+TEST ! stat source_deletions_me/file
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/file
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/file
d2787b
+TEST ! stat source_deletions_me/dir1/dir2
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/dir1/dir2
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/dir1/dir2
d2787b
+TEST ! stat source_deletions_me/dir1
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_me/dir1
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_me/dir1
d2787b
+
d2787b
+#Test if the files created as part of access are healed correctly
d2787b
+r=$(get_file_type source_creations_me/fifo)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/fifo
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/fifo
d2787b
+TEST [ -p source_creations_me/fifo ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_me/block)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/block
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/block
d2787b
+EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}1/source_creations_me/block
d2787b
+EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}0/source_creations_me/block
d2787b
+TEST [ -b source_creations_me/block ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_me/char)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/char
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/char
d2787b
+EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}1/source_creations_me/char
d2787b
+EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}0/source_creations_me/char
d2787b
+TEST [ -c source_creations_me/char ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_me/file)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/file
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/file
d2787b
+TEST [ -f source_creations_me/file ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_me/slink)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/slink
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/slink
d2787b
+TEST [ -h source_creations_me/slink ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_me/dir1/dir2)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/dir1/dir2
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/dir1/dir2
d2787b
+TEST [ -d source_creations_me/dir1/dir2 ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_me/dir1)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/dir1
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/dir1
d2787b
+TEST [ -d source_creations_me/dir1 ]
d2787b
+
d2787b
+#Trigger heal and check _heal dirs are healed properly
d2787b
+#Trigger change in event generation number. That way inodes would get refreshed during lookup
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}1
d2787b
+$CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+
d2787b
+TEST stat spb_heal
d2787b
+TEST stat spb_me_heal
d2787b
+TEST stat fool_heal
d2787b
+TEST stat fool_me
d2787b
+TEST stat v1_fool_heal
d2787b
+TEST stat v1_fool_me
d2787b
+TEST stat source_deletions_heal
d2787b
+TEST stat source_deletions_me
d2787b
+TEST stat source_self_accusing
d2787b
+TEST stat source_creations_heal
d2787b
+TEST stat source_creations_me
d2787b
+TEST stat v1_dirty_heal
d2787b
+TEST stat v1_dirty_me
d2787b
+TEST $CLI volume stop $V0
d2787b
+TEST rm -rf $B0/${V0}{0,1}/.glusterfs/indices/xattrop/*
d2787b
+
d2787b
+$CLI volume start $V0
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+
d2787b
+#Create base entry in indices/xattrop
d2787b
+echo "Data" > $M0/FILE
d2787b
+rm -f $M0/FILE
d2787b
+EXPECT "1" count_index_entries $B0/${V0}0
d2787b
+EXPECT "1" count_index_entries $B0/${V0}1
d2787b
+
d2787b
+TEST $CLI volume stop $V0;
d2787b
+
d2787b
+#Create entries for fool_heal and fool_me to ensure they are fully healed and dirty xattrs erased, before triggering index heal
d2787b
+create_brick_xattrop_entry $B0/${V0}0 fool_heal fool_me source_creations_heal/dir1
d2787b
+
d2787b
+$CLI volume start $V0
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+
d2787b
+$CLI volume heal $V0 enable
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
d2787b
+
d2787b
+TEST $CLI volume heal $V0;
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals spb_heal spb_me_heal fool_heal fool_me v1_fool_heal v1_fool_me source_deletions_heal source_deletions_me source_creations_heal source_creations_me v1_dirty_heal v1_dirty_me source_self_accusing
d2787b
+
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 spb_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 spb_me_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 fool_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 fool_me
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_fool_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_fool_me
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_deletions_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_deletions_me
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_self_accusing
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_creations_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_creations_me
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_dirty_heal
d2787b
+EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_dirty_me
d2787b
+
d2787b
+#Don't access the files/dirs from mount point as that may cause self-heals
d2787b
+# Check if conservative merges happened correctly on heal dirs
d2787b
+TEST stat $B0/${V0}0/spb_heal/1
d2787b
+TEST stat $B0/${V0}1/spb_heal/1
d2787b
+
d2787b
+TEST stat $B0/${V0}0/spb_heal/0
d2787b
+TEST stat $B0/${V0}1/spb_heal/0
d2787b
+
d2787b
+TEST stat $B0/${V0}0/fool_heal/1
d2787b
+TEST stat $B0/${V0}1/fool_heal/1
d2787b
+
d2787b
+TEST stat $B0/${V0}0/fool_heal/0
d2787b
+TEST stat $B0/${V0}1/fool_heal/0
d2787b
+
d2787b
+TEST stat $B0/${V0}0/v1_fool_heal/0
d2787b
+TEST stat $B0/${V0}1/v1_fool_heal/0
d2787b
+
d2787b
+TEST stat $B0/${V0}0/v1_fool_heal/1
d2787b
+TEST stat $B0/${V0}1/v1_fool_heal/1
d2787b
+
d2787b
+TEST stat $B0/${V0}0/v1_dirty_heal/0
d2787b
+TEST stat $B0/${V0}1/v1_dirty_heal/0
d2787b
+
d2787b
+#Check if files that have gfid-mismatches in spb are giving EIO
d2787b
+TEST ! stat spb/0
d2787b
+
d2787b
+#Check if stale files are deleted on access
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/fifo
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/fifo
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/block
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/block
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/char
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/char
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/file
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/file
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/file
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/file
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/dir1/dir2
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/dir1/dir2
d2787b
+TEST ! stat $B0/${V0}0/source_deletions_heal/dir1
d2787b
+TEST ! stat $B0/${V0}1/source_deletions_heal/dir1
d2787b
+
d2787b
+#Check if stale files are deleted on access
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/fifo
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/fifo
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/block
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/block
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/char
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/char
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/file
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/file
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/file
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/file
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/dir1/dir2
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/dir1/dir2
d2787b
+TEST ! stat $B0/${V0}0/source_self_accusing/dir1
d2787b
+TEST ! stat $B0/${V0}1/source_self_accusing/dir1
d2787b
+
d2787b
+#Test if the files created as part of full self-heal correctly
d2787b
+r=$(get_file_type $B0/${V0}0/source_creations_heal/fifo)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/fifo
d2787b
+TEST [ -p $B0/${V0}0/source_creations_heal/fifo ]
d2787b
+EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}1/source_creations_heal/block
d2787b
+EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}0/source_creations_heal/block
d2787b
+
d2787b
+r=$(get_file_type $B0/${V0}0/source_creations_heal/block)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/block
d2787b
+
d2787b
+r=$(get_file_type $B0/${V0}0/source_creations_heal/char)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/char
d2787b
+EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}1/source_creations_heal/char
d2787b
+EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}0/source_creations_heal/char
d2787b
+
d2787b
+r=$(get_file_type $B0/${V0}0/source_creations_heal/file)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/file
d2787b
+TEST [ -f $B0/${V0}0/source_creations_heal/file ]
d2787b
+
d2787b
+r=$(get_file_type source_creations_heal/file $B0/${V0}0/slink)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/file slink
d2787b
+TEST [ -h $B0/${V0}0/source_creations_heal/slink ]
d2787b
+
d2787b
+r=$(get_file_type $B0/${V0}0/source_creations_heal/dir1/dir2)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/dir1/dir2
d2787b
+TEST [ -d $B0/${V0}0/source_creations_heal/dir1/dir2 ]
d2787b
+
d2787b
+r=$(get_file_type $B0/${V0}0/source_creations_heal/dir1)
d2787b
+EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/dir1
d2787b
+TEST [ -d $B0/${V0}0/source_creations_heal/dir1 ]
d2787b
+
d2787b
+cd -
d2787b
+
d2787b
+#Anonymous directory shouldn't be created
d2787b
+TEST mkdir $M0/rename-dir
d2787b
+before_rename=$(STAT_INO $B0/${V0}1/rename-dir)
d2787b
+TEST kill_brick $V0 $H0 $B0/${V0}1
d2787b
+TEST mv $M0/rename-dir $M0/new-name
d2787b
+TEST $CLI volume start $V0 force
d2787b
+#Since features.ctime is not enabled by default in downstream, the below test
d2787b
+#will fail. If ctime feature is enabled, there will be trusted.glusterfs.mdata
d2787b
+#xattr set which will differ for the parent in the gfid split-brain scenario
d2787b
+#and when lookup is triggered, the gfid gets added to indices/xattrop leading
d2787b
+#the below test to pass in upstream. Hence commenting it here.
d2787b
+#'spb' is in split-brain so pending-heal-count will be 2
d2787b
+#EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0
d2787b
+after_rename=$(STAT_INO $B0/${V0}1/new-name)
d2787b
+EXPECT "0" echo $(ls -a $B0/${V0}0/ | grep anonymous-inode | wc -l)
d2787b
+EXPECT "0" echo $(ls -a $B0/${V0}1/ | grep anonymous-inode | wc -l)
d2787b
+EXPECT_NOT "$before_rename" echo $after_rename
d2787b
+cleanup
d2787b
diff --git a/tests/basic/afr/rename-data-loss.t b/tests/basic/afr/rename-data-loss.t
d2787b
new file mode 100644
d2787b
index 0000000..256ee2a
d2787b
--- /dev/null
d2787b
+++ b/tests/basic/afr/rename-data-loss.t
d2787b
@@ -0,0 +1,72 @@
d2787b
+#!/bin/bash
d2787b
+#Self-heal tests
d2787b
+. $(dirname $0)/../../include.rc
d2787b
+. $(dirname $0)/../../volume.rc
d2787b
+. $(dirname $0)/../../afr.rc
d2787b
+
d2787b
+cleanup;
d2787b
+
d2787b
+TEST glusterd
d2787b
+TEST pidof glusterd
d2787b
+TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1}
d2787b
+TEST $CLI volume set $V0 write-behind off
d2787b
+TEST $CLI volume set $V0 self-heal-daemon off
d2787b
+TEST $CLI volume set $V0 data-self-heal off
d2787b
+TEST $CLI volume set $V0 metadata-self-heal off
d2787b
+TEST $CLI volume set $V0 entry-self-heal off
d2787b
+TEST $CLI volume start $V0
d2787b
+EXPECT 'Started' volinfo_field $V0 'Status'
d2787b
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0;
d2787b
+
d2787b
+cd $M0
d2787b
+TEST `echo "line1" >> file1`
d2787b
+TEST mkdir dir1
d2787b
+TEST mkdir dir2
d2787b
+TEST mkdir -p dir1/dira/dirb
d2787b
+TEST `echo "line1">>dir1/dira/dirb/file1`
d2787b
+TEST mkdir delete_me
d2787b
+TEST `echo "line1" >> delete_me/file1`
d2787b
+
d2787b
+#brick0 has witnessed the second write while brick1 is down.
d2787b
+TEST kill_brick $V0 $H0 $B0/brick1
d2787b
+TEST `echo "line2" >> file1`
d2787b
+TEST `echo "line2" >> dir1/dira/dirb/file1`
d2787b
+TEST `echo "line2" >> delete_me/file1`
d2787b
+
d2787b
+#Toggle the bricks that are up/down.
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1
d2787b
+TEST kill_brick $V0 $H0 $B0/brick0
d2787b
+
d2787b
+#Rename when the 'source' brick0 for data-selfheals is down.
d2787b
+mv file1 file2
d2787b
+mv dir1/dira dir2
d2787b
+
d2787b
+#Delete a dir when brick0 is down.
d2787b
+rm -rf delete_me
d2787b
+cd -
d2787b
+
d2787b
+#Bring everything up and trigger heal
d2787b
+TEST $CLI volume set $V0 self-heal-daemon on
d2787b
+TEST $CLI volume start $V0 force
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0
d2787b
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
d2787b
+TEST $CLI volume heal $V0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/brick0
d2787b
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/brick1
d2787b
+
d2787b
+#Remount to avoid reading from caches
d2787b
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
d2787b
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0;
d2787b
+EXPECT "line2" tail -1 $M0/file2
d2787b
+EXPECT "line2" tail -1 $M0/dir2/dira/dirb/file1
d2787b
+TEST ! stat $M0/delete_me/file1
d2787b
+TEST ! stat $M0/delete_me
d2787b
+
d2787b
+anon_inode_name=$(ls -a $B0/brick0 | grep glusterfs-anonymous-inode)
d2787b
+TEST [[ -d $B0/brick0/$anon_inode_name ]]
d2787b
+TEST [[ -d $B0/brick1/$anon_inode_name ]]
d2787b
+cleanup
d2787b
diff --git a/tests/bugs/replicate/bug-1744548-heal-timeout.t b/tests/bugs/replicate/bug-1744548-heal-timeout.t
d2787b
index c208112..0115350 100644
d2787b
--- a/tests/bugs/replicate/bug-1744548-heal-timeout.t
d2787b
+++ b/tests/bugs/replicate/bug-1744548-heal-timeout.t
d2787b
@@ -25,14 +25,14 @@ TEST ! $CLI volume heal $V0
d2787b
 TEST $CLI volume profile $V0 start
d2787b
 TEST $CLI volume profile $V0 info clear
d2787b
 TEST $CLI volume heal $V0 enable
d2787b
-# Each brick does 3 opendirs, corresponding to dirty, xattrop and entry-changes
d2787b
-EXPECT_WITHIN $HEAL_TIMEOUT "^333$" get_cumulative_opendir_count
d2787b
+# Each brick does 4 opendirs, corresponding to dirty, xattrop and entry-changes, anonymous-inode
d2787b
+EXPECT_WITHIN 4 "^444$" get_cumulative_opendir_count
d2787b
 
d2787b
 # Check that a change in heal-timeout is honoured immediately.
d2787b
 TEST $CLI volume set $V0 cluster.heal-timeout 5
d2787b
 sleep 10
d2787b
 # Two crawls must have happened.
d2787b
-EXPECT_WITHIN $HEAL_TIMEOUT "^999$" get_cumulative_opendir_count
d2787b
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "^121212$" get_cumulative_opendir_count
d2787b
 
d2787b
 # shd must not heal if it is disabled and heal-timeout is changed.
d2787b
 TEST $CLI volume heal $V0 disable
d2787b
diff --git a/tests/features/trash.t b/tests/features/trash.t
d2787b
index 472e909..da5b50b 100755
d2787b
--- a/tests/features/trash.t
d2787b
+++ b/tests/features/trash.t
d2787b
@@ -94,105 +94,105 @@ wildcard_not_exists() {
d2787b
         if [ $? -eq 0 ]; then echo "Y"; else echo "N"; fi
d2787b
 }
d2787b
 
d2787b
-# testing glusterd [1-3]
d2787b
+# testing glusterd
d2787b
 TEST glusterd
d2787b
 TEST pidof glusterd
d2787b
 TEST $CLI volume info
d2787b
 
d2787b
-# creating distributed volume [4]
d2787b
+# creating distributed volume
d2787b
 TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2}
d2787b
 
d2787b
-# checking volume status [5-7]
d2787b
+# checking volume status
d2787b
 EXPECT "$V0" volinfo_field $V0 'Volume Name'
d2787b
 EXPECT 'Created' volinfo_field $V0 'Status'
d2787b
 EXPECT '2' brick_count $V0
d2787b
 
d2787b
-# test without enabling trash translator [8]
d2787b
+# test without enabling trash translator
d2787b
 TEST start_vol $V0 $M0
d2787b
 
d2787b
-# test on enabling trash translator [9-10]
d2787b
+# test on enabling trash translator
d2787b
 TEST $CLI volume set $V0 features.trash on
d2787b
 EXPECT 'on' volinfo_field $V0 'features.trash'
d2787b
 
d2787b
-# files directly under mount point [11]
d2787b
+# files directly under mount point
d2787b
 create_files $M0/file1 $M0/file2
d2787b
 TEST file_exists $V0 file1 file2
d2787b
 
d2787b
-# perform unlink [12]
d2787b
+# perform unlink
d2787b
 TEST unlink_op file1
d2787b
 
d2787b
-# perform truncate [13]
d2787b
+# perform truncate
d2787b
 TEST truncate_op file2 4
d2787b
 
d2787b
-# create files directory hierarchy and check [14]
d2787b
+# create files directory hierarchy and check
d2787b
 mkdir -p $M0/1/2/3
d2787b
 create_files $M0/1/2/3/foo1 $M0/1/2/3/foo2
d2787b
 TEST file_exists $V0 1/2/3/foo1 1/2/3/foo2
d2787b
 
d2787b
-# perform unlink [15]
d2787b
+# perform unlink
d2787b
 TEST unlink_op 1/2/3/foo1
d2787b
 
d2787b
-# perform truncate [16]
d2787b
+# perform truncate
d2787b
 TEST truncate_op 1/2/3/foo2 4
d2787b
 
d2787b
 # create a directory for eliminate pattern
d2787b
 mkdir $M0/a
d2787b
 
d2787b
-# set the eliminate pattern [17-18]
d2787b
+# set the eliminate pattern
d2787b
 TEST $CLI volume set $V0 features.trash-eliminate-path /a
d2787b
 EXPECT '/a' volinfo_field $V0 'features.trash-eliminate-path'
d2787b
 
d2787b
-# create two files and check [19]
d2787b
+# create two files and check
d2787b
 create_files $M0/a/test1 $M0/a/test2
d2787b
 TEST file_exists $V0 a/test1 a/test2
d2787b
 
d2787b
-# remove from eliminate pattern [20]
d2787b
+# remove from eliminate pattern
d2787b
 rm -f $M0/a/test1
d2787b
 EXPECT "Y" wildcard_not_exists $M0/.trashcan/a/test1*
d2787b
 
d2787b
-# truncate from eliminate path [21-23]
d2787b
+# truncate from eliminate path
d2787b
 truncate -s 2 $M0/a/test2
d2787b
 TEST [ -e $M0/a/test2 ]
d2787b
 TEST [ `ls -l $M0/a/test2 | awk '{print $5}'` -eq 2 ]
d2787b
 EXPECT "Y" wildcard_not_exists $M0/.trashcan/a/test2*
d2787b
 
d2787b
-# set internal op on [24-25]
d2787b
+# set internal op on
d2787b
 TEST $CLI volume set $V0 features.trash-internal-op on
d2787b
 EXPECT 'on' volinfo_field $V0 'features.trash-internal-op'
d2787b
 
d2787b
-# again create two files and check [26]
d2787b
+# again create two files and check
d2787b
 create_files $M0/inop1 $M0/inop2
d2787b
 TEST file_exists $V0 inop1 inop2
d2787b
 
d2787b
-# perform unlink [27]
d2787b
+# perform unlink
d2787b
 TEST unlink_op inop1
d2787b
 
d2787b
-# perform truncate [28]
d2787b
+# perform truncate
d2787b
 TEST truncate_op inop2 4
d2787b
 
d2787b
-# remove one brick and restart the volume [28-31]
d2787b
+# remove one brick and restart the volume
d2787b
 TEST $CLI volume remove-brick $V0 $H0:$B0/${V0}2 force
d2787b
 EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
d2787b
 TEST $CLI volume stop $V0
d2787b
 TEST start_vol $V0 $M0 $M0/.trashcan
d2787b
 
d2787b
-# again create two files and check [33]
d2787b
+# again create two files and check
d2787b
 create_files $M0/rebal1 $M0/rebal2
d2787b
 TEST file_exists $V0 rebal1 rebal2
d2787b
 
d2787b
-# add one brick [34-35]
d2787b
+# add one brick
d2787b
 TEST $CLI volume add-brick $V0 $H0:$B0/${V0}3
d2787b
 TEST [ -d $B0/${V0}3 ]
d2787b
 
d2787b
 
d2787b
-# perform rebalance [36]
d2787b
+# perform rebalance
d2787b
 TEST $CLI volume rebalance $V0 start force
d2787b
 EXPECT_WITHIN $REBALANCE_TIMEOUT "0" rebalance_completed
d2787b
 
d2787b
 #Find out which file was migrated to the new brick
d2787b
 file_name=$(ls $B0/${V0}3/rebal*| xargs basename)
d2787b
 
d2787b
-# check whether rebalance was succesful [37-40]
d2787b
+# check whether rebalance was succesful
d2787b
 EXPECT "Y" wildcard_exists $B0/${V0}3/$file_name*
d2787b
 EXPECT "Y" wildcard_exists $B0/${V0}1/.trashcan/internal_op/$file_name*
d2787b
 
d2787b
@@ -201,52 +201,42 @@ EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
d2787b
 # force required in case rebalance is not over
d2787b
 TEST $CLI volume stop $V0 force
d2787b
 
d2787b
-# create a replicated volume [41]
d2787b
+# create a replicated volume
d2787b
 TEST $CLI volume create $V1 replica 2 $H0:$B0/${V1}{1,2}
d2787b
 
d2787b
-# checking volume status [42-45]
d2787b
+# checking volume status
d2787b
 EXPECT "$V1" volinfo_field $V1 'Volume Name'
d2787b
 EXPECT 'Replicate' volinfo_field $V1 'Type'
d2787b
 EXPECT 'Created' volinfo_field $V1 'Status'
d2787b
 EXPECT '2' brick_count $V1
d2787b
 
d2787b
-# enable trash with options and start the replicate volume by disabling automatic self-heal [46-50]
d2787b
+# enable trash with options and start the replicate volume by disabling automatic self-heal
d2787b
 TEST $CLI volume set $V1 features.trash on
d2787b
 TEST $CLI volume set $V1 features.trash-internal-op on
d2787b
 EXPECT 'on' volinfo_field $V1 'features.trash'
d2787b
 EXPECT 'on' volinfo_field $V1 'features.trash-internal-op'
d2787b
 TEST start_vol $V1 $M1 $M1/.trashcan
d2787b
 
d2787b
-# mount and check for trash directory [51]
d2787b
+# mount and check for trash directory
d2787b
 TEST [ -d $M1/.trashcan/internal_op ]
d2787b
 
d2787b
-# create a file and check [52]
d2787b
+# create a file and check
d2787b
 touch $M1/self
d2787b
 TEST [ -e $B0/${V1}1/self -a -e $B0/${V1}2/self ]
d2787b
 
d2787b
-# kill one brick and delete the file from mount point [53-54]
d2787b
+# kill one brick and delete the file from mount point
d2787b
 kill_brick $V1 $H0 $B0/${V1}1
d2787b
 EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "1" online_brick_count
d2787b
 rm -f $M1/self
d2787b
 EXPECT "Y" wildcard_exists $B0/${V1}2/.trashcan/self*
d2787b
 
d2787b
-# force start the volume and trigger the self-heal manually [55-57]
d2787b
-TEST $CLI volume start $V1 force
d2787b
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" online_brick_count
d2787b
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
d2787b
-# Since we created the file under root of the volume, it will be
d2787b
-# healed automatically
d2787b
-
d2787b
-# check for the removed file in trashcan [58]
d2787b
-EXPECT_WITHIN $HEAL_TIMEOUT "Y" wildcard_exists $B0/${V1}1/.trashcan/internal_op/self*
d2787b
-
d2787b
-# check renaming of trash directory through cli [59-62]
d2787b
+# check renaming of trash directory through cli
d2787b
 TEST $CLI volume set $V0 trash-dir abc
d2787b
 TEST start_vol $V0 $M0 $M0/abc
d2787b
 TEST [ -e $M0/abc -a ! -e $M0/.trashcan ]
d2787b
 EXPECT "Y" wildcard_exists $B0/${V0}1/abc/internal_op/rebal*
d2787b
 
d2787b
-# ensure that rename and delete operation on trash directory fails [63-65]
d2787b
+# ensure that rename and delete operation on trash directory fails
d2787b
 rm -rf $M0/abc/internal_op
d2787b
 TEST [ -e $M0/abc/internal_op ]
d2787b
 rm -rf $M0/abc/
d2787b
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c
d2787b
index 90b4f14..6f2da11 100644
d2787b
--- a/xlators/cluster/afr/src/afr-common.c
d2787b
+++ b/xlators/cluster/afr/src/afr-common.c
d2787b
@@ -47,6 +47,41 @@ afr_quorum_errno(afr_private_t *priv)
d2787b
     return ENOTCONN;
d2787b
 }
d2787b
 
d2787b
+gf_boolean_t
d2787b
+afr_is_private_directory(afr_private_t *priv, uuid_t pargfid, const char *name,
d2787b
+                         pid_t pid)
d2787b
+{
d2787b
+    if (!__is_root_gfid(pargfid)) {
d2787b
+        return _gf_false;
d2787b
+    }
d2787b
+
d2787b
+    if (strcmp(name, GF_REPLICATE_TRASH_DIR) == 0) {
d2787b
+        /*For backward compatibility /.landfill is private*/
d2787b
+        return _gf_true;
d2787b
+    }
d2787b
+
d2787b
+    if (pid == GF_CLIENT_PID_GSYNCD) {
d2787b
+        /*geo-rep needs to create/sync private directory on slave because
d2787b
+         * it appears in changelog*/
d2787b
+        return _gf_false;
d2787b
+    }
d2787b
+
d2787b
+    if (pid == GF_CLIENT_PID_GLFS_HEAL || pid == GF_CLIENT_PID_SELF_HEALD) {
d2787b
+        if (strcmp(name, priv->anon_inode_name) == 0) {
d2787b
+            /* anonymous-inode dir is private*/
d2787b
+            return _gf_true;
d2787b
+        }
d2787b
+    } else {
d2787b
+        if (strncmp(name, AFR_ANON_DIR_PREFIX, strlen(AFR_ANON_DIR_PREFIX)) ==
d2787b
+            0) {
d2787b
+            /* anonymous-inode dir prefix is private for geo-rep to work*/
d2787b
+            return _gf_true;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+    return _gf_false;
d2787b
+}
d2787b
+
d2787b
 int
d2787b
 afr_fav_child_reset_sink_xattrs(void *opaque);
d2787b
 
d2787b
@@ -3301,11 +3336,10 @@ afr_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xattr_req)
d2787b
         return 0;
d2787b
     }
d2787b
 
d2787b
-    if (__is_root_gfid(loc->parent->gfid)) {
d2787b
-        if (!strcmp(loc->name, GF_REPLICATE_TRASH_DIR)) {
d2787b
-            op_errno = EPERM;
d2787b
-            goto out;
d2787b
-        }
d2787b
+    if (afr_is_private_directory(this->private, loc->parent->gfid, loc->name,
d2787b
+                                 frame->root->pid)) {
d2787b
+        op_errno = EPERM;
d2787b
+        goto out;
d2787b
     }
d2787b
 
d2787b
     local = AFR_FRAME_INIT(frame, op_errno);
d2787b
@@ -4832,6 +4866,7 @@ afr_priv_dump(xlator_t *this)
d2787b
                        priv->background_self_heal_count);
d2787b
     gf_proc_dump_write("healers", "%d", priv->healers);
d2787b
     gf_proc_dump_write("read-hash-mode", "%d", priv->hash_mode);
d2787b
+    gf_proc_dump_write("use-anonymous-inode", "%d", priv->use_anon_inode);
d2787b
     if (priv->quorum_count == AFR_QUORUM_AUTO) {
d2787b
         gf_proc_dump_write("quorum-type", "auto");
d2787b
     } else if (priv->quorum_count == 0) {
d2787b
@@ -5792,6 +5827,7 @@ afr_priv_destroy(afr_private_t *priv)
d2787b
     GF_FREE(priv->local);
d2787b
     GF_FREE(priv->pending_key);
d2787b
     GF_FREE(priv->children);
d2787b
+    GF_FREE(priv->anon_inode);
d2787b
     GF_FREE(priv->child_up);
d2787b
     GF_FREE(priv->child_latency);
d2787b
     LOCK_DESTROY(&priv->lock);
d2787b
diff --git a/xlators/cluster/afr/src/afr-dir-read.c b/xlators/cluster/afr/src/afr-dir-read.c
d2787b
index 6307b63..d64b6a9 100644
d2787b
--- a/xlators/cluster/afr/src/afr-dir-read.c
d2787b
+++ b/xlators/cluster/afr/src/afr-dir-read.c
d2787b
@@ -158,8 +158,8 @@ afr_validate_read_subvol(inode_t *inode, xlator_t *this, int par_read_subvol)
d2787b
 }
d2787b
 
d2787b
 static void
d2787b
-afr_readdir_transform_entries(gf_dirent_t *subvol_entries, int subvol,
d2787b
-                              gf_dirent_t *entries, fd_t *fd)
d2787b
+afr_readdir_transform_entries(call_frame_t *frame, gf_dirent_t *subvol_entries,
d2787b
+                              int subvol, gf_dirent_t *entries, fd_t *fd)
d2787b
 {
d2787b
     int ret = -1;
d2787b
     gf_dirent_t *entry = NULL;
d2787b
@@ -177,8 +177,8 @@ afr_readdir_transform_entries(gf_dirent_t *subvol_entries, int subvol,
d2787b
 
d2787b
     list_for_each_entry_safe(entry, tmp, &subvol_entries->list, list)
d2787b
     {
d2787b
-        if (__is_root_gfid(fd->inode->gfid) &&
d2787b
-            !strcmp(entry->d_name, GF_REPLICATE_TRASH_DIR)) {
d2787b
+        if (afr_is_private_directory(priv, fd->inode->gfid, entry->d_name,
d2787b
+                                     frame->root->pid)) {
d2787b
             continue;
d2787b
         }
d2787b
 
d2787b
@@ -222,8 +222,8 @@ afr_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
     }
d2787b
 
d2787b
     if (op_ret >= 0)
d2787b
-        afr_readdir_transform_entries(subvol_entries, (long)cookie, &entries,
d2787b
-                                      local->fd);
d2787b
+        afr_readdir_transform_entries(frame, subvol_entries, (long)cookie,
d2787b
+                                      &entries, local->fd);
d2787b
 
d2787b
     AFR_STACK_UNWIND(readdir, frame, op_ret, op_errno, &entries, xdata);
d2787b
 
d2787b
diff --git a/xlators/cluster/afr/src/afr-self-heal-common.c b/xlators/cluster/afr/src/afr-self-heal-common.c
d2787b
index 9b6575f..0a8a7fd 100644
d2787b
--- a/xlators/cluster/afr/src/afr-self-heal-common.c
d2787b
+++ b/xlators/cluster/afr/src/afr-self-heal-common.c
d2787b
@@ -2753,3 +2753,185 @@ afr_choose_source_by_policy(afr_private_t *priv, unsigned char *sources,
d2787b
 out:
d2787b
     return source;
d2787b
 }
d2787b
+
d2787b
+static int
d2787b
+afr_anon_inode_mkdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
+                         int32_t op_ret, int32_t op_errno, inode_t *inode,
d2787b
+                         struct iatt *buf, struct iatt *preparent,
d2787b
+                         struct iatt *postparent, dict_t *xdata)
d2787b
+{
d2787b
+    afr_local_t *local = frame->local;
d2787b
+    int i = (long)cookie;
d2787b
+
d2787b
+    local->replies[i].valid = 1;
d2787b
+    local->replies[i].op_ret = op_ret;
d2787b
+    local->replies[i].op_errno = op_errno;
d2787b
+    if (op_ret == 0) {
d2787b
+        local->op_ret = 0;
d2787b
+        local->replies[i].poststat = *buf;
d2787b
+        local->replies[i].preparent = *preparent;
d2787b
+        local->replies[i].postparent = *postparent;
d2787b
+    }
d2787b
+    if (xdata) {
d2787b
+        local->replies[i].xdata = dict_ref(xdata);
d2787b
+    }
d2787b
+
d2787b
+    syncbarrier_wake(&local->barrier);
d2787b
+    return 0;
d2787b
+}
d2787b
+
d2787b
+int
d2787b
+afr_anon_inode_create(xlator_t *this, int child, inode_t **linked_inode)
d2787b
+{
d2787b
+    call_frame_t *frame = NULL;
d2787b
+    afr_local_t *local = NULL;
d2787b
+    afr_private_t *priv = this->private;
d2787b
+    unsigned char *mkdir_on = alloca0(priv->child_count);
d2787b
+    unsigned char *lookup_on = alloca0(priv->child_count);
d2787b
+    loc_t loc = {0};
d2787b
+    int32_t op_errno = 0;
d2787b
+    int32_t child_op_errno = 0;
d2787b
+    struct iatt iatt = {0};
d2787b
+    dict_t *xdata = NULL;
d2787b
+    uuid_t anon_inode_gfid = {0};
d2787b
+    int mkdir_count = 0;
d2787b
+    int i = 0;
d2787b
+
d2787b
+    /*Try to mkdir everywhere and return success if the dir exists on 'child'
d2787b
+     */
d2787b
+
d2787b
+    if (!priv->use_anon_inode) {
d2787b
+        op_errno = EINVAL;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    frame = afr_frame_create(this, &op_errno);
d2787b
+    if (op_errno) {
d2787b
+        goto out;
d2787b
+    }
d2787b
+    local = frame->local;
d2787b
+    if (!local->child_up[child]) {
d2787b
+        /*Other bricks may need mkdir so don't error out yet*/
d2787b
+        child_op_errno = ENOTCONN;
d2787b
+    }
d2787b
+    gf_uuid_parse(priv->anon_gfid_str, anon_inode_gfid);
d2787b
+    for (i = 0; i < priv->child_count; i++) {
d2787b
+        if (!local->child_up[i])
d2787b
+            continue;
d2787b
+
d2787b
+        if (priv->anon_inode[i]) {
d2787b
+            mkdir_on[i] = 0;
d2787b
+        } else {
d2787b
+            mkdir_on[i] = 1;
d2787b
+            mkdir_count++;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+    if (mkdir_count == 0) {
d2787b
+        *linked_inode = inode_find(this->itable, anon_inode_gfid);
d2787b
+        if (*linked_inode) {
d2787b
+            op_errno = 0;
d2787b
+            goto out;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+    loc.parent = inode_ref(this->itable->root);
d2787b
+    loc.name = priv->anon_inode_name;
d2787b
+    loc.inode = inode_new(this->itable);
d2787b
+    if (!loc.inode) {
d2787b
+        op_errno = ENOMEM;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    xdata = dict_new();
d2787b
+    if (!xdata) {
d2787b
+        op_errno = ENOMEM;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    op_errno = -dict_set_gfuuid(xdata, "gfid-req", anon_inode_gfid, _gf_true);
d2787b
+    if (op_errno) {
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    if (mkdir_count == 0) {
d2787b
+        memcpy(lookup_on, local->child_up, priv->child_count);
d2787b
+        goto lookup;
d2787b
+    }
d2787b
+
d2787b
+    AFR_ONLIST(mkdir_on, frame, afr_anon_inode_mkdir_cbk, mkdir, &loc, 0755, 0,
d2787b
+               xdata);
d2787b
+
d2787b
+    for (i = 0; i < priv->child_count; i++) {
d2787b
+        if (!mkdir_on[i]) {
d2787b
+            continue;
d2787b
+        }
d2787b
+
d2787b
+        if (local->replies[i].op_ret == 0) {
d2787b
+            priv->anon_inode[i] = 1;
d2787b
+            iatt = local->replies[i].poststat;
d2787b
+        } else if (local->replies[i].op_ret < 0 &&
d2787b
+                   local->replies[i].op_errno == EEXIST) {
d2787b
+            lookup_on[i] = 1;
d2787b
+        } else if (i == child) {
d2787b
+            child_op_errno = local->replies[i].op_errno;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+    if (AFR_COUNT(lookup_on, priv->child_count) == 0) {
d2787b
+        goto link;
d2787b
+    }
d2787b
+
d2787b
+lookup:
d2787b
+    AFR_ONLIST(lookup_on, frame, afr_selfheal_discover_cbk, lookup, &loc,
d2787b
+               xdata);
d2787b
+    for (i = 0; i < priv->child_count; i++) {
d2787b
+        if (!lookup_on[i]) {
d2787b
+            continue;
d2787b
+        }
d2787b
+
d2787b
+        if (local->replies[i].op_ret == 0) {
d2787b
+            if (gf_uuid_compare(anon_inode_gfid,
d2787b
+                                local->replies[i].poststat.ia_gfid) == 0) {
d2787b
+                priv->anon_inode[i] = 1;
d2787b
+                iatt = local->replies[i].poststat;
d2787b
+            } else {
d2787b
+                if (i == child)
d2787b
+                    child_op_errno = EINVAL;
d2787b
+                gf_msg(this->name, GF_LOG_ERROR, 0, AFR_MSG_INVALID_DATA,
d2787b
+                       "%s has gfid: %s", priv->anon_inode_name,
d2787b
+                       uuid_utoa(local->replies[i].poststat.ia_gfid));
d2787b
+            }
d2787b
+        } else if (i == child) {
d2787b
+            child_op_errno = local->replies[i].op_errno;
d2787b
+        }
d2787b
+    }
d2787b
+link:
d2787b
+    if (!gf_uuid_is_null(iatt.ia_gfid)) {
d2787b
+        *linked_inode = inode_link(loc.inode, loc.parent, loc.name, &iatt);
d2787b
+        if (*linked_inode) {
d2787b
+            op_errno = 0;
d2787b
+            inode_lookup(*linked_inode);
d2787b
+        } else {
d2787b
+            op_errno = ENOMEM;
d2787b
+        }
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+out:
d2787b
+    if (xdata)
d2787b
+        dict_unref(xdata);
d2787b
+    loc_wipe(&loc;;
d2787b
+    /*child_op_errno takes precedence*/
d2787b
+    if (child_op_errno == 0) {
d2787b
+        child_op_errno = op_errno;
d2787b
+    }
d2787b
+
d2787b
+    if (child_op_errno && *linked_inode) {
d2787b
+        inode_unref(*linked_inode);
d2787b
+        *linked_inode = NULL;
d2787b
+    }
d2787b
+    if (frame)
d2787b
+        AFR_STACK_DESTROY(frame);
d2787b
+    return -child_op_errno;
d2787b
+}
d2787b
diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c
d2787b
index 00b5b2d..20b07dd 100644
d2787b
--- a/xlators/cluster/afr/src/afr-self-heal-entry.c
d2787b
+++ b/xlators/cluster/afr/src/afr-self-heal-entry.c
d2787b
@@ -16,54 +16,170 @@
d2787b
 #include <glusterfs/syncop-utils.h>
d2787b
 #include <glusterfs/events.h>
d2787b
 
d2787b
-static int
d2787b
-afr_selfheal_entry_delete(xlator_t *this, inode_t *dir, const char *name,
d2787b
-                          inode_t *inode, int child, struct afr_reply *replies)
d2787b
+int
d2787b
+afr_selfheal_entry_anon_inode(xlator_t *this, inode_t *dir, const char *name,
d2787b
+                              inode_t *inode, int child,
d2787b
+                              struct afr_reply *replies,
d2787b
+                              gf_boolean_t *anon_inode)
d2787b
 {
d2787b
     afr_private_t *priv = NULL;
d2787b
+    afr_local_t *local = NULL;
d2787b
     xlator_t *subvol = NULL;
d2787b
     int ret = 0;
d2787b
+    int i = 0;
d2787b
+    char g[64] = {0};
d2787b
+    unsigned char *lookup_success = NULL;
d2787b
+    call_frame_t *frame = NULL;
d2787b
+    loc_t loc2 = {
d2787b
+        0,
d2787b
+    };
d2787b
     loc_t loc = {
d2787b
         0,
d2787b
     };
d2787b
-    char g[64];
d2787b
 
d2787b
     priv = this->private;
d2787b
-
d2787b
     subvol = priv->children[child];
d2787b
+    lookup_success = alloca0(priv->child_count);
d2787b
+    uuid_utoa_r(replies[child].poststat.ia_gfid, g);
d2787b
+    loc.inode = inode_new(inode->table);
d2787b
+    if (!loc.inode) {
d2787b
+        ret = -ENOMEM;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    if (replies[child].poststat.ia_type == IA_IFDIR) {
d2787b
+        /* This directory may have sub-directory hierarchy which may need to
d2787b
+         * be preserved for subsequent heals. So unconditionally move the
d2787b
+         * directory to anonymous-inode directory*/
d2787b
+        *anon_inode = _gf_true;
d2787b
+        goto anon_inode;
d2787b
+    }
d2787b
+
d2787b
+    frame = afr_frame_create(this, &ret;;
d2787b
+    if (!frame) {
d2787b
+        ret = -ret;
d2787b
+        goto out;
d2787b
+    }
d2787b
+    local = frame->local;
d2787b
+    gf_uuid_copy(loc.gfid, replies[child].poststat.ia_gfid);
d2787b
+    AFR_ONLIST(local->child_up, frame, afr_selfheal_discover_cbk, lookup, &loc,
d2787b
+               NULL);
d2787b
+    for (i = 0; i < priv->child_count; i++) {
d2787b
+        if (local->replies[i].op_ret == 0) {
d2787b
+            lookup_success[i] = 1;
d2787b
+        } else if (local->replies[i].op_errno != ENOENT &&
d2787b
+                   local->replies[i].op_errno != ESTALE) {
d2787b
+            ret = -local->replies[i].op_errno;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+    if (priv->quorum_count) {
d2787b
+        if (afr_has_quorum(lookup_success, this, NULL)) {
d2787b
+            *anon_inode = _gf_true;
d2787b
+        }
d2787b
+    } else if (AFR_COUNT(lookup_success, priv->child_count) > 1) {
d2787b
+        *anon_inode = _gf_true;
d2787b
+    } else if (ret) {
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+anon_inode:
d2787b
+    if (!*anon_inode) {
d2787b
+        ret = 0;
d2787b
+        goto out;
d2787b
+    }
d2787b
 
d2787b
     loc.parent = inode_ref(dir);
d2787b
     gf_uuid_copy(loc.pargfid, dir->gfid);
d2787b
     loc.name = name;
d2787b
-    loc.inode = inode_ref(inode);
d2787b
 
d2787b
-    if (replies[child].valid && replies[child].op_ret == 0) {
d2787b
-        switch (replies[child].poststat.ia_type) {
d2787b
-            case IA_IFDIR:
d2787b
-                gf_msg(this->name, GF_LOG_WARNING, 0,
d2787b
-                       AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
-                       "expunging dir %s/%s (%s) on %s", uuid_utoa(dir->gfid),
d2787b
-                       name, uuid_utoa_r(replies[child].poststat.ia_gfid, g),
d2787b
-                       subvol->name);
d2787b
-                ret = syncop_rmdir(subvol, &loc, 1, NULL, NULL);
d2787b
-                break;
d2787b
-            default:
d2787b
-                gf_msg(this->name, GF_LOG_WARNING, 0,
d2787b
-                       AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
-                       "expunging file %s/%s (%s) on %s", uuid_utoa(dir->gfid),
d2787b
-                       name, uuid_utoa_r(replies[child].poststat.ia_gfid, g),
d2787b
-                       subvol->name);
d2787b
-                ret = syncop_unlink(subvol, &loc, NULL, NULL);
d2787b
-                break;
d2787b
-        }
d2787b
+    ret = afr_anon_inode_create(this, child, &loc2.parent);
d2787b
+    if (ret < 0)
d2787b
+        goto out;
d2787b
+
d2787b
+    loc2.name = g;
d2787b
+    ret = syncop_rename(subvol, &loc, &loc2, NULL, NULL);
d2787b
+    if (ret < 0) {
d2787b
+        gf_msg(this->name, GF_LOG_WARNING, -ret, AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
+               "Rename to %s dir %s/%s (%s) on %s failed",
d2787b
+               priv->anon_inode_name, uuid_utoa(dir->gfid), name, g,
d2787b
+               subvol->name);
d2787b
+    } else {
d2787b
+        gf_msg(this->name, GF_LOG_WARNING, 0, AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
+               "Rename to %s dir %s/%s (%s) on %s successful",
d2787b
+               priv->anon_inode_name, uuid_utoa(dir->gfid), name, g,
d2787b
+               subvol->name);
d2787b
     }
d2787b
 
d2787b
+out:
d2787b
     loc_wipe(&loc;;
d2787b
+    loc_wipe(&loc2);
d2787b
+    if (frame) {
d2787b
+        AFR_STACK_DESTROY(frame);
d2787b
+    }
d2787b
 
d2787b
     return ret;
d2787b
 }
d2787b
 
d2787b
 int
d2787b
+afr_selfheal_entry_delete(xlator_t *this, inode_t *dir, const char *name,
d2787b
+                          inode_t *inode, int child, struct afr_reply *replies)
d2787b
+{
d2787b
+    char g[64] = {0};
d2787b
+    afr_private_t *priv = NULL;
d2787b
+    xlator_t *subvol = NULL;
d2787b
+    int ret = 0;
d2787b
+    loc_t loc = {
d2787b
+        0,
d2787b
+    };
d2787b
+    gf_boolean_t anon_inode = _gf_false;
d2787b
+
d2787b
+    priv = this->private;
d2787b
+    subvol = priv->children[child];
d2787b
+
d2787b
+    if ((!replies[child].valid) || (replies[child].op_ret < 0)) {
d2787b
+        /*Nothing to do*/
d2787b
+        ret = 0;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    if (priv->use_anon_inode) {
d2787b
+        ret = afr_selfheal_entry_anon_inode(this, dir, name, inode, child,
d2787b
+                                            replies, &anon_inode);
d2787b
+        if (ret < 0 || anon_inode)
d2787b
+            goto out;
d2787b
+    }
d2787b
+
d2787b
+    loc.parent = inode_ref(dir);
d2787b
+    loc.inode = inode_new(inode->table);
d2787b
+    if (!loc.inode) {
d2787b
+        ret = -ENOMEM;
d2787b
+        goto out;
d2787b
+    }
d2787b
+    loc.name = name;
d2787b
+    switch (replies[child].poststat.ia_type) {
d2787b
+        case IA_IFDIR:
d2787b
+            gf_msg(this->name, GF_LOG_WARNING, 0, AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
+                   "expunging dir %s/%s (%s) on %s", uuid_utoa(dir->gfid), name,
d2787b
+                   uuid_utoa_r(replies[child].poststat.ia_gfid, g),
d2787b
+                   subvol->name);
d2787b
+            ret = syncop_rmdir(subvol, &loc, 1, NULL, NULL);
d2787b
+            break;
d2787b
+        default:
d2787b
+            gf_msg(this->name, GF_LOG_WARNING, 0, AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
+                   "expunging file %s/%s (%s) on %s", uuid_utoa(dir->gfid),
d2787b
+                   name, uuid_utoa_r(replies[child].poststat.ia_gfid, g),
d2787b
+                   subvol->name);
d2787b
+            ret = syncop_unlink(subvol, &loc, NULL, NULL);
d2787b
+            break;
d2787b
+    }
d2787b
+
d2787b
+out:
d2787b
+    loc_wipe(&loc;;
d2787b
+    return ret;
d2787b
+}
d2787b
+
d2787b
+int
d2787b
 afr_selfheal_recreate_entry(call_frame_t *frame, int dst, int source,
d2787b
                             unsigned char *sources, inode_t *dir,
d2787b
                             const char *name, inode_t *inode,
d2787b
@@ -76,6 +192,9 @@ afr_selfheal_recreate_entry(call_frame_t *frame, int dst, int source,
d2787b
     loc_t srcloc = {
d2787b
         0,
d2787b
     };
d2787b
+    loc_t anonloc = {
d2787b
+        0,
d2787b
+    };
d2787b
     xlator_t *this = frame->this;
d2787b
     afr_private_t *priv = NULL;
d2787b
     dict_t *xdata = NULL;
d2787b
@@ -86,15 +205,18 @@ afr_selfheal_recreate_entry(call_frame_t *frame, int dst, int source,
d2787b
         0,
d2787b
     };
d2787b
     unsigned char *newentry = NULL;
d2787b
+    char iatt_uuid_str[64] = {0};
d2787b
+    char dir_uuid_str[64] = {0};
d2787b
 
d2787b
     priv = this->private;
d2787b
     iatt = &replies[source].poststat;
d2787b
+    uuid_utoa_r(iatt->ia_gfid, iatt_uuid_str);
d2787b
     if (iatt->ia_type == IA_INVAL || gf_uuid_is_null(iatt->ia_gfid)) {
d2787b
         gf_msg(this->name, GF_LOG_ERROR, 0, AFR_MSG_SELF_HEAL_FAILED,
d2787b
                "Invalid ia_type (%d) or gfid(%s). source brick=%d, "
d2787b
                "pargfid=%s, name=%s",
d2787b
-               iatt->ia_type, uuid_utoa(iatt->ia_gfid), source,
d2787b
-               uuid_utoa(dir->gfid), name);
d2787b
+               iatt->ia_type, iatt_uuid_str, source,
d2787b
+               uuid_utoa_r(dir->gfid, dir_uuid_str), name);
d2787b
         ret = -EINVAL;
d2787b
         goto out;
d2787b
     }
d2787b
@@ -119,14 +241,24 @@ afr_selfheal_recreate_entry(call_frame_t *frame, int dst, int source,
d2787b
 
d2787b
     srcloc.inode = inode_ref(inode);
d2787b
     gf_uuid_copy(srcloc.gfid, iatt->ia_gfid);
d2787b
-    if (iatt->ia_type != IA_IFDIR)
d2787b
-        ret = syncop_lookup(priv->children[dst], &srcloc, 0, 0, 0, 0);
d2787b
-    if (iatt->ia_type == IA_IFDIR || ret == -ENOENT || ret == -ESTALE) {
d2787b
+    ret = syncop_lookup(priv->children[dst], &srcloc, 0, 0, 0, 0);
d2787b
+    if (ret == -ENOENT || ret == -ESTALE) {
d2787b
         newentry[dst] = 1;
d2787b
         ret = afr_selfheal_newentry_mark(frame, this, inode, source, replies,
d2787b
                                          sources, newentry);
d2787b
         if (ret)
d2787b
             goto out;
d2787b
+    } else if (ret == 0 && iatt->ia_type == IA_IFDIR && priv->use_anon_inode) {
d2787b
+        // Try rename from hidden directory
d2787b
+        ret = afr_anon_inode_create(this, dst, &anonloc.parent);
d2787b
+        if (ret < 0)
d2787b
+            goto out;
d2787b
+        anonloc.inode = inode_ref(inode);
d2787b
+        anonloc.name = iatt_uuid_str;
d2787b
+        ret = syncop_rename(priv->children[dst], &anonloc, &loc, NULL, NULL);
d2787b
+        if (ret == -ENOENT || ret == -ESTALE)
d2787b
+            ret = -1; /*This sets 'mismatch' to true*/
d2787b
+        goto out;
d2787b
     }
d2787b
 
d2787b
     mode = st_mode_from_ia(iatt->ia_prot, iatt->ia_type);
d2787b
@@ -165,6 +297,7 @@ out:
d2787b
     GF_FREE(linkname);
d2787b
     loc_wipe(&loc;;
d2787b
     loc_wipe(&srcloc);
d2787b
+    loc_wipe(&anonloc);
d2787b
     return ret;
d2787b
 }
d2787b
 
d2787b
@@ -580,6 +713,11 @@ afr_selfheal_entry_dirent(call_frame_t *frame, xlator_t *this, fd_t *fd,
d2787b
 
d2787b
     priv = this->private;
d2787b
 
d2787b
+    if (afr_is_private_directory(priv, fd->inode->gfid, name,
d2787b
+                                 GF_CLIENT_PID_SELF_HEALD)) {
d2787b
+        return 0;
d2787b
+    }
d2787b
+
d2787b
     xattr = dict_new();
d2787b
     if (!xattr)
d2787b
         return -ENOMEM;
d2787b
@@ -628,7 +766,7 @@ afr_selfheal_entry_dirent(call_frame_t *frame, xlator_t *this, fd_t *fd,
d2787b
                                           replies);
d2787b
 
d2787b
         if ((ret == 0) && (priv->esh_granular) && parent_idx_inode) {
d2787b
-            ret = afr_shd_index_purge(subvol, parent_idx_inode, name,
d2787b
+            ret = afr_shd_entry_purge(subvol, parent_idx_inode, name,
d2787b
                                       inode->ia_type);
d2787b
             /* Why is ret force-set to 0? We do not care about
d2787b
              * index purge failing for full heal as it is quite
d2787b
@@ -758,10 +896,6 @@ afr_selfheal_entry_do_subvol(call_frame_t *frame, xlator_t *this, fd_t *fd,
d2787b
             if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
d2787b
                 continue;
d2787b
 
d2787b
-            if (__is_root_gfid(fd->inode->gfid) &&
d2787b
-                !strcmp(entry->d_name, GF_REPLICATE_TRASH_DIR))
d2787b
-                continue;
d2787b
-
d2787b
             ret = afr_selfheal_entry_dirent(iter_frame, this, fd, entry->d_name,
d2787b
                                             loc.inode, subvol,
d2787b
                                             local->need_full_crawl);
d2787b
@@ -824,7 +958,7 @@ afr_selfheal_entry_granular_dirent(xlator_t *subvol, gf_dirent_t *entry,
d2787b
         /* The name indices under the pgfid index dir are guaranteed
d2787b
          * to be regular files. Hence the hardcoding.
d2787b
          */
d2787b
-        afr_shd_index_purge(subvol, parent->inode, entry->d_name, IA_IFREG);
d2787b
+        afr_shd_entry_purge(subvol, parent->inode, entry->d_name, IA_IFREG);
d2787b
         ret = 0;
d2787b
         goto out;
d2787b
     }
d2787b
diff --git a/xlators/cluster/afr/src/afr-self-heal-name.c b/xlators/cluster/afr/src/afr-self-heal-name.c
d2787b
index dace071..51e3d8c 100644
d2787b
--- a/xlators/cluster/afr/src/afr-self-heal-name.c
d2787b
+++ b/xlators/cluster/afr/src/afr-self-heal-name.c
d2787b
@@ -98,21 +98,12 @@ __afr_selfheal_name_expunge(xlator_t *this, inode_t *parent, uuid_t pargfid,
d2787b
                             const char *bname, inode_t *inode,
d2787b
                             struct afr_reply *replies)
d2787b
 {
d2787b
-    loc_t loc = {
d2787b
-        0,
d2787b
-    };
d2787b
     int i = 0;
d2787b
     afr_private_t *priv = NULL;
d2787b
-    char g[64];
d2787b
     int ret = 0;
d2787b
 
d2787b
     priv = this->private;
d2787b
 
d2787b
-    loc.parent = inode_ref(parent);
d2787b
-    gf_uuid_copy(loc.pargfid, pargfid);
d2787b
-    loc.name = bname;
d2787b
-    loc.inode = inode_ref(inode);
d2787b
-
d2787b
     for (i = 0; i < priv->child_count; i++) {
d2787b
         if (!replies[i].valid)
d2787b
             continue;
d2787b
@@ -120,30 +111,10 @@ __afr_selfheal_name_expunge(xlator_t *this, inode_t *parent, uuid_t pargfid,
d2787b
         if (replies[i].op_ret)
d2787b
             continue;
d2787b
 
d2787b
-        switch (replies[i].poststat.ia_type) {
d2787b
-            case IA_IFDIR:
d2787b
-                gf_msg(this->name, GF_LOG_WARNING, 0,
d2787b
-                       AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
-                       "expunging dir %s/%s (%s) on %s", uuid_utoa(pargfid),
d2787b
-                       bname, uuid_utoa_r(replies[i].poststat.ia_gfid, g),
d2787b
-                       priv->children[i]->name);
d2787b
-
d2787b
-                ret |= syncop_rmdir(priv->children[i], &loc, 1, NULL, NULL);
d2787b
-                break;
d2787b
-            default:
d2787b
-                gf_msg(this->name, GF_LOG_WARNING, 0,
d2787b
-                       AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
-                       "expunging file %s/%s (%s) on %s", uuid_utoa(pargfid),
d2787b
-                       bname, uuid_utoa_r(replies[i].poststat.ia_gfid, g),
d2787b
-                       priv->children[i]->name);
d2787b
-
d2787b
-                ret |= syncop_unlink(priv->children[i], &loc, NULL, NULL);
d2787b
-                break;
d2787b
-        }
d2787b
+        ret |= afr_selfheal_entry_delete(this, parent, bname, inode, i,
d2787b
+                                         replies);
d2787b
     }
d2787b
 
d2787b
-    loc_wipe(&loc;;
d2787b
-
d2787b
     return ret;
d2787b
 }
d2787b
 
d2787b
diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h
d2787b
index 8f6fb00..c8dc384 100644
d2787b
--- a/xlators/cluster/afr/src/afr-self-heal.h
d2787b
+++ b/xlators/cluster/afr/src/afr-self-heal.h
d2787b
@@ -370,4 +370,9 @@ gf_boolean_t
d2787b
 afr_is_file_empty_on_all_children(afr_private_t *priv,
d2787b
                                   struct afr_reply *replies);
d2787b
 
d2787b
+int
d2787b
+afr_selfheal_entry_delete(xlator_t *this, inode_t *dir, const char *name,
d2787b
+                          inode_t *inode, int child, struct afr_reply *replies);
d2787b
+int
d2787b
+afr_anon_inode_create(xlator_t *this, int child, inode_t **linked_inode);
d2787b
 #endif /* !_AFR_SELFHEAL_H */
d2787b
diff --git a/xlators/cluster/afr/src/afr-self-heald.c b/xlators/cluster/afr/src/afr-self-heald.c
d2787b
index 95ac5f2..939a135 100644
d2787b
--- a/xlators/cluster/afr/src/afr-self-heald.c
d2787b
+++ b/xlators/cluster/afr/src/afr-self-heald.c
d2787b
@@ -222,7 +222,7 @@ out:
d2787b
 }
d2787b
 
d2787b
 int
d2787b
-afr_shd_index_purge(xlator_t *subvol, inode_t *inode, char *name,
d2787b
+afr_shd_entry_purge(xlator_t *subvol, inode_t *inode, char *name,
d2787b
                     ia_type_t type)
d2787b
 {
d2787b
     int ret = 0;
d2787b
@@ -422,7 +422,7 @@ afr_shd_index_heal(xlator_t *subvol, gf_dirent_t *entry, loc_t *parent,
d2787b
     ret = afr_shd_selfheal(healer, healer->subvol, gfid);
d2787b
 
d2787b
     if (ret == -ENOENT || ret == -ESTALE)
d2787b
-        afr_shd_index_purge(subvol, parent->inode, entry->d_name, val);
d2787b
+        afr_shd_entry_purge(subvol, parent->inode, entry->d_name, val);
d2787b
 
d2787b
     if (ret == 2)
d2787b
         /* If bricks crashed in pre-op after creating indices/xattrop
d2787b
@@ -798,6 +798,176 @@ afr_bricks_available_for_heal(afr_private_t *priv)
d2787b
     return _gf_true;
d2787b
 }
d2787b
 
d2787b
+static int
d2787b
+afr_shd_anon_inode_cleaner(xlator_t *subvol, gf_dirent_t *entry, loc_t *parent,
d2787b
+                           void *data)
d2787b
+{
d2787b
+    struct subvol_healer *healer = data;
d2787b
+    afr_private_t *priv = healer->this->private;
d2787b
+    call_frame_t *frame = NULL;
d2787b
+    afr_local_t *local = NULL;
d2787b
+    int ret = 0;
d2787b
+    loc_t loc = {0};
d2787b
+    int count = 0;
d2787b
+    int i = 0;
d2787b
+    int op_errno = 0;
d2787b
+    struct iatt *iatt = NULL;
d2787b
+    gf_boolean_t multiple_links = _gf_false;
d2787b
+    unsigned char *gfid_present = alloca0(priv->child_count);
d2787b
+    unsigned char *entry_present = alloca0(priv->child_count);
d2787b
+    char *type = "file";
d2787b
+
d2787b
+    frame = afr_frame_create(healer->this, &ret;;
d2787b
+    if (!frame) {
d2787b
+        ret = -ret;
d2787b
+        goto out;
d2787b
+    }
d2787b
+    local = frame->local;
d2787b
+    if (AFR_COUNT(local->child_up, priv->child_count) != priv->child_count) {
d2787b
+        gf_msg_debug(healer->this->name, 0,
d2787b
+                     "Not all bricks are up. Skipping "
d2787b
+                     "cleanup of %s on %s",
d2787b
+                     entry->d_name, subvol->name);
d2787b
+        ret = 0;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    loc.inode = inode_new(parent->inode->table);
d2787b
+    if (!loc.inode) {
d2787b
+        ret = -ENOMEM;
d2787b
+        goto out;
d2787b
+    }
d2787b
+    ret = gf_uuid_parse(entry->d_name, loc.gfid);
d2787b
+    if (ret) {
d2787b
+        ret = 0;
d2787b
+        goto out;
d2787b
+    }
d2787b
+    AFR_ONLIST(local->child_up, frame, afr_selfheal_discover_cbk, lookup, &loc,
d2787b
+               NULL);
d2787b
+    for (i = 0; i < priv->child_count; i++) {
d2787b
+        if (local->replies[i].op_ret == 0) {
d2787b
+            count++;
d2787b
+            gfid_present[i] = 1;
d2787b
+            iatt = &local->replies[i].poststat;
d2787b
+            if (iatt->ia_type == IA_IFDIR) {
d2787b
+                type = "dir";
d2787b
+            }
d2787b
+
d2787b
+            if (i == healer->subvol) {
d2787b
+                if (local->replies[i].poststat.ia_nlink > 1) {
d2787b
+                    multiple_links = _gf_true;
d2787b
+                }
d2787b
+            }
d2787b
+        } else if (local->replies[i].op_errno != ENOENT &&
d2787b
+                   local->replies[i].op_errno != ESTALE) {
d2787b
+            /*We don't have complete view. Skip the entry*/
d2787b
+            gf_msg_debug(healer->this->name, local->replies[i].op_errno,
d2787b
+                         "Skipping cleanup of %s on %s", entry->d_name,
d2787b
+                         subvol->name);
d2787b
+            ret = 0;
d2787b
+            goto out;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+    /*Inode is deleted from subvol*/
d2787b
+    if (count == 1 || (iatt->ia_type != IA_IFDIR && multiple_links)) {
d2787b
+        gf_msg(healer->this->name, GF_LOG_WARNING, 0,
d2787b
+               AFR_MSG_EXPUNGING_FILE_OR_DIR, "expunging %s %s/%s on %s", type,
d2787b
+               priv->anon_inode_name, entry->d_name, subvol->name);
d2787b
+        ret = afr_shd_entry_purge(subvol, parent->inode, entry->d_name,
d2787b
+                                  iatt->ia_type);
d2787b
+        if (ret == -ENOENT || ret == -ESTALE)
d2787b
+            ret = 0;
d2787b
+    } else if (count > 1) {
d2787b
+        loc_wipe(&loc;;
d2787b
+        loc.parent = inode_ref(parent->inode);
d2787b
+        loc.name = entry->d_name;
d2787b
+        loc.inode = inode_new(parent->inode->table);
d2787b
+        if (!loc.inode) {
d2787b
+            ret = -ENOMEM;
d2787b
+            goto out;
d2787b
+        }
d2787b
+        AFR_ONLIST(local->child_up, frame, afr_selfheal_discover_cbk, lookup,
d2787b
+                   &loc, NULL);
d2787b
+        count = 0;
d2787b
+        for (i = 0; i < priv->child_count; i++) {
d2787b
+            if (local->replies[i].op_ret == 0) {
d2787b
+                count++;
d2787b
+                entry_present[i] = 1;
d2787b
+                iatt = &local->replies[i].poststat;
d2787b
+            } else if (local->replies[i].op_errno != ENOENT &&
d2787b
+                       local->replies[i].op_errno != ESTALE) {
d2787b
+                /*We don't have complete view. Skip the entry*/
d2787b
+                gf_msg_debug(healer->this->name, local->replies[i].op_errno,
d2787b
+                             "Skipping cleanup of %s on %s", entry->d_name,
d2787b
+                             subvol->name);
d2787b
+                ret = 0;
d2787b
+                goto out;
d2787b
+            }
d2787b
+        }
d2787b
+        for (i = 0; i < priv->child_count; i++) {
d2787b
+            if (gfid_present[i] && !entry_present[i]) {
d2787b
+                /*Entry is not anonymous on at least one subvol*/
d2787b
+                gf_msg_debug(healer->this->name, 0,
d2787b
+                             "Valid entry present on %s "
d2787b
+                             "Skipping cleanup of %s on %s",
d2787b
+                             priv->children[i]->name, entry->d_name,
d2787b
+                             subvol->name);
d2787b
+                ret = 0;
d2787b
+                goto out;
d2787b
+            }
d2787b
+        }
d2787b
+
d2787b
+        gf_msg(healer->this->name, GF_LOG_WARNING, 0,
d2787b
+               AFR_MSG_EXPUNGING_FILE_OR_DIR,
d2787b
+               "expunging %s %s/%s on all subvols", type, priv->anon_inode_name,
d2787b
+               entry->d_name);
d2787b
+        ret = 0;
d2787b
+        for (i = 0; i < priv->child_count; i++) {
d2787b
+            op_errno = -afr_shd_entry_purge(priv->children[i], loc.parent,
d2787b
+                                            entry->d_name, iatt->ia_type);
d2787b
+            if (op_errno != ENOENT && op_errno != ESTALE) {
d2787b
+                ret |= -op_errno;
d2787b
+            }
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+out:
d2787b
+    if (frame)
d2787b
+        AFR_STACK_DESTROY(frame);
d2787b
+    loc_wipe(&loc;;
d2787b
+    return ret;
d2787b
+}
d2787b
+
d2787b
+static void
d2787b
+afr_cleanup_anon_inode_dir(struct subvol_healer *healer)
d2787b
+{
d2787b
+    int ret = 0;
d2787b
+    call_frame_t *frame = NULL;
d2787b
+    afr_private_t *priv = healer->this->private;
d2787b
+    loc_t loc = {0};
d2787b
+
d2787b
+    ret = afr_anon_inode_create(healer->this, healer->subvol, &loc.inode);
d2787b
+    if (ret)
d2787b
+        goto out;
d2787b
+
d2787b
+    frame = afr_frame_create(healer->this, &ret;;
d2787b
+    if (!frame) {
d2787b
+        ret = -ret;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    ret = syncop_mt_dir_scan(frame, priv->children[healer->subvol], &loc,
d2787b
+                             GF_CLIENT_PID_SELF_HEALD, healer,
d2787b
+                             afr_shd_anon_inode_cleaner, NULL,
d2787b
+                             priv->shd.max_threads, priv->shd.wait_qlength);
d2787b
+out:
d2787b
+    if (frame)
d2787b
+        AFR_STACK_DESTROY(frame);
d2787b
+    loc_wipe(&loc;;
d2787b
+    return;
d2787b
+}
d2787b
+
d2787b
 void *
d2787b
 afr_shd_index_healer(void *data)
d2787b
 {
d2787b
@@ -854,6 +1024,10 @@ afr_shd_index_healer(void *data)
d2787b
             sleep(1);
d2787b
         } while (ret > 0);
d2787b
 
d2787b
+        if (ret == 0) {
d2787b
+            afr_cleanup_anon_inode_dir(healer);
d2787b
+        }
d2787b
+
d2787b
         if (pre_crawl_xdata && !healer->crawl_event.heal_failed_count) {
d2787b
             afr_shd_ta_check_and_unset_xattrs(this, &loc, healer,
d2787b
                                               pre_crawl_xdata);
d2787b
diff --git a/xlators/cluster/afr/src/afr-self-heald.h b/xlators/cluster/afr/src/afr-self-heald.h
d2787b
index 1990539..acd567e 100644
d2787b
--- a/xlators/cluster/afr/src/afr-self-heald.h
d2787b
+++ b/xlators/cluster/afr/src/afr-self-heald.h
d2787b
@@ -70,6 +70,6 @@ afr_shd_gfid_to_path(xlator_t *this, xlator_t *subvol, uuid_t gfid,
d2787b
                      char **path_p);
d2787b
 
d2787b
 int
d2787b
-afr_shd_index_purge(xlator_t *subvol, inode_t *inode, char *name,
d2787b
+afr_shd_entry_purge(xlator_t *subvol, inode_t *inode, char *name,
d2787b
                     ia_type_t type);
d2787b
 #endif /* !_AFR_SELF_HEALD_H */
d2787b
diff --git a/xlators/cluster/afr/src/afr.c b/xlators/cluster/afr/src/afr.c
d2787b
index bfa464f..33fe4d8 100644
d2787b
--- a/xlators/cluster/afr/src/afr.c
d2787b
+++ b/xlators/cluster/afr/src/afr.c
d2787b
@@ -135,6 +135,27 @@ set_data_self_heal_algorithm(afr_private_t *priv, char *algo)
d2787b
     }
d2787b
 }
d2787b
 
d2787b
+void
d2787b
+afr_handle_anon_inode_options(afr_private_t *priv, dict_t *options)
d2787b
+{
d2787b
+    char *volfile_id_str = NULL;
d2787b
+    uuid_t anon_inode_gfid = {0};
d2787b
+
d2787b
+    /*If volume id is not present don't enable anything*/
d2787b
+    if (dict_get_str(options, "volume-id", &volfile_id_str))
d2787b
+        return;
d2787b
+    GF_ASSERT(strlen(AFR_ANON_DIR_PREFIX) + strlen(volfile_id_str) <= NAME_MAX);
d2787b
+    /*anon_inode_name is not supposed to change once assigned*/
d2787b
+    if (!priv->anon_inode_name[0]) {
d2787b
+        snprintf(priv->anon_inode_name, sizeof(priv->anon_inode_name), "%s-%s",
d2787b
+                 AFR_ANON_DIR_PREFIX, volfile_id_str);
d2787b
+        gf_uuid_parse(volfile_id_str, anon_inode_gfid);
d2787b
+        /*Flip a bit to make sure volfile-id and anon-gfid are not same*/
d2787b
+        anon_inode_gfid[0] ^= 1;
d2787b
+        uuid_utoa_r(anon_inode_gfid, priv->anon_gfid_str);
d2787b
+    }
d2787b
+}
d2787b
+
d2787b
 int
d2787b
 reconfigure(xlator_t *this, dict_t *options)
d2787b
 {
d2787b
@@ -287,6 +308,10 @@ reconfigure(xlator_t *this, dict_t *options)
d2787b
         consistent_io = _gf_false;
d2787b
     priv->consistent_io = consistent_io;
d2787b
 
d2787b
+    afr_handle_anon_inode_options(priv, options);
d2787b
+
d2787b
+    GF_OPTION_RECONF("use-anonymous-inode", priv->use_anon_inode, options, bool,
d2787b
+                     out);
d2787b
     if (priv->shd.enabled) {
d2787b
         if ((priv->shd.enabled != enabled_old) ||
d2787b
             (timeout_old != priv->shd.timeout))
d2787b
@@ -535,7 +560,9 @@ init(xlator_t *this)
d2787b
 
d2787b
     GF_OPTION_INIT("consistent-metadata", priv->consistent_metadata, bool, out);
d2787b
     GF_OPTION_INIT("consistent-io", priv->consistent_io, bool, out);
d2787b
+    afr_handle_anon_inode_options(priv, this->options);
d2787b
 
d2787b
+    GF_OPTION_INIT("use-anonymous-inode", priv->use_anon_inode, bool, out);
d2787b
     if (priv->quorum_count != 0)
d2787b
         priv->consistent_io = _gf_false;
d2787b
 
d2787b
@@ -547,13 +574,16 @@ init(xlator_t *this)
d2787b
         goto out;
d2787b
     }
d2787b
 
d2787b
+    priv->anon_inode = GF_CALLOC(sizeof(unsigned char), child_count,
d2787b
+                                 gf_afr_mt_char);
d2787b
+
d2787b
     priv->child_up = GF_CALLOC(sizeof(unsigned char), child_count,
d2787b
                                gf_afr_mt_char);
d2787b
 
d2787b
     priv->child_latency = GF_MALLOC(sizeof(*priv->child_latency) * child_count,
d2787b
                                     gf_afr_mt_child_latency_t);
d2787b
 
d2787b
-    if (!priv->child_up || !priv->child_latency) {
d2787b
+    if (!priv->child_up || !priv->child_latency || !priv->anon_inode) {
d2787b
         ret = -ENOMEM;
d2787b
         goto out;
d2787b
     }
d2787b
@@ -1218,6 +1248,14 @@ struct volume_options options[] = {
d2787b
      .tags = {"replicate"},
d2787b
      .description = "This option exists only for backward compatibility "
d2787b
                     "and configuring it doesn't have any effect"},
d2787b
+    {.key = {"use-anonymous-inode"},
d2787b
+     .type = GF_OPTION_TYPE_BOOL,
d2787b
+     .default_value = "no",
d2787b
+     .op_version = {GD_OP_VERSION_7_0},
d2787b
+     .flags = OPT_FLAG_CLIENT_OPT | OPT_FLAG_SETTABLE,
d2787b
+     .tags = {"replicate"},
d2787b
+     .description = "Setting this option heals directory renames efficiently"},
d2787b
+
d2787b
     {.key = {NULL}},
d2787b
 };
d2787b
 
d2787b
diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h
d2787b
index 3a2b26d..6a9a763 100644
d2787b
--- a/xlators/cluster/afr/src/afr.h
d2787b
+++ b/xlators/cluster/afr/src/afr.h
d2787b
@@ -40,6 +40,8 @@
d2787b
 #define AFR_TA_DOM_MODIFY "afr.ta.dom-modify"
d2787b
 
d2787b
 #define AFR_HALO_MAX_LATENCY 99999
d2787b
+#define AFR_ANON_DIR_PREFIX ".glusterfs-anonymous-inode"
d2787b
+
d2787b
 
d2787b
 #define PFLAG_PENDING (1 << 0)
d2787b
 #define PFLAG_SBRAIN (1 << 1)
d2787b
@@ -155,6 +157,7 @@ typedef struct _afr_private {
d2787b
     struct list_head ta_waitq;
d2787b
     struct list_head ta_onwireq;
d2787b
 
d2787b
+    unsigned char *anon_inode;
d2787b
     unsigned char *child_up;
d2787b
     int64_t *child_latency;
d2787b
     unsigned char *local;
d2787b
@@ -240,6 +243,11 @@ typedef struct _afr_private {
d2787b
     gf_boolean_t esh_granular;
d2787b
     gf_boolean_t consistent_io;
d2787b
     gf_boolean_t data_self_heal; /* on/off */
d2787b
+    gf_boolean_t use_anon_inode;
d2787b
+
d2787b
+    /*For anon-inode handling */
d2787b
+    char anon_inode_name[NAME_MAX + 1];
d2787b
+    char anon_gfid_str[UUID_SIZE + 1];
d2787b
 } afr_private_t;
d2787b
 
d2787b
 typedef enum {
d2787b
@@ -1341,4 +1349,7 @@ afr_selfheal_childup(xlator_t *this, afr_private_t *priv);
d2787b
 void
d2787b
 afr_fill_success_replies(afr_local_t *local, afr_private_t *priv,
d2787b
                          unsigned char *replies);
d2787b
+gf_boolean_t
d2787b
+afr_is_private_directory(afr_private_t *priv, uuid_t pargfid, const char *name,
d2787b
+                         pid_t pid);
d2787b
 #endif /* __AFR_H__ */
d2787b
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
d2787b
index 094a71f..1920284 100644
d2787b
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
d2787b
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
d2787b
@@ -3867,6 +3867,38 @@ out:
d2787b
 }
d2787b
 
d2787b
 static int
d2787b
+set_volfile_id_option(volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
d2787b
+                      int clusters)
d2787b
+{
d2787b
+    xlator_t *xlator = NULL;
d2787b
+    int i = 0;
d2787b
+    int ret = -1;
d2787b
+    glusterd_conf_t *conf = NULL;
d2787b
+    xlator_t *this = NULL;
d2787b
+
d2787b
+    this = THIS;
d2787b
+    GF_VALIDATE_OR_GOTO("glusterd", this, out);
d2787b
+    conf = this->private;
d2787b
+    GF_VALIDATE_OR_GOTO(this->name, conf, out);
d2787b
+
d2787b
+    if (conf->op_version < GD_OP_VERSION_7_1)
d2787b
+        return 0;
d2787b
+    xlator = first_of(graph);
d2787b
+
d2787b
+    for (i = 0; i < clusters; i++) {
d2787b
+        ret = xlator_set_fixed_option(xlator, "volume-id",
d2787b
+                                      uuid_utoa(volinfo->volume_id));
d2787b
+        if (ret)
d2787b
+            goto out;
d2787b
+
d2787b
+        xlator = xlator->next;
d2787b
+    }
d2787b
+
d2787b
+out:
d2787b
+    return ret;
d2787b
+}
d2787b
+
d2787b
+static int
d2787b
 volgen_graph_build_afr_clusters(volgen_graph_t *graph,
d2787b
                                 glusterd_volinfo_t *volinfo)
d2787b
 {
d2787b
@@ -3906,6 +3938,13 @@ volgen_graph_build_afr_clusters(volgen_graph_t *graph,
d2787b
         clusters = -1;
d2787b
         goto out;
d2787b
     }
d2787b
+
d2787b
+    ret = set_volfile_id_option(graph, volinfo, clusters);
d2787b
+    if (ret) {
d2787b
+        clusters = -1;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
     if (!volinfo->arbiter_count)
d2787b
         goto out;
d2787b
 
d2787b
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
d2787b
index 62acadf..c1ca190 100644
d2787b
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
d2787b
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
d2787b
@@ -3789,4 +3789,10 @@ struct volopt_map_entry glusterd_volopt_map[] = {
d2787b
      .voltype = "features/cloudsync",
d2787b
      .op_version = GD_OP_VERSION_7_0,
d2787b
      .flags = VOLOPT_FLAG_CLIENT_OPT},
d2787b
+
d2787b
+    {.key = "cluster.use-anonymous-inode",
d2787b
+     .voltype = "cluster/replicate",
d2787b
+     .op_version = GD_OP_VERSION_7_1,
d2787b
+     .value = "yes",
d2787b
+     .flags = VOLOPT_FLAG_CLIENT_OPT},
d2787b
     {.key = NULL}};
d2787b
-- 
d2787b
1.8.3.1
d2787b