887953
From 93ef66173442aaf4aeaeb161c6d6108eda54014a Mon Sep 17 00:00:00 2001
887953
From: Krutika Dhananjay <kdhananj@redhat.com>
887953
Date: Thu, 12 Apr 2018 15:47:00 +0530
887953
Subject: [PATCH 430/444] features/shard: Perform shards deletion in the
887953
 background
887953
887953
> Upstream: https://review.gluster.org/19970
887953
> BUG: 1568521
887953
> Change-Id: Ia83117230c9dd7d0d9cae05235644f8475e97bc3
887953
887953
A synctask is created that would scan the indices from
887953
.shard/.remove_me, to delete the shards associated with the
887953
gfid corresponding to the index bname and the rate of deletion
887953
is controlled by the option features.shard-deletion-rate whose
887953
default value is 100.
887953
The task is launched on two accounts:
887953
1. when shard receives its first-ever lookup on the volume
887953
2. when a rename or unlink deleted an inode
887953
887953
Change-Id: Ia83117230c9dd7d0d9cae05235644f8475e97bc3
887953
BUG: 1520882
887953
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
887953
Reviewed-on: https://code.engineering.redhat.com/gerrit/154864
887953
Tested-by: RHGS Build Bot <nigelb@redhat.com>
887953
Reviewed-by: Xavi Hernandez <xhernandez@redhat.com>
887953
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
887953
---
887953
 libglusterfs/src/globals.h                      |   1 +
887953
 tests/bugs/shard/bug-1568521-EEXIST.t           |  30 +-
887953
 tests/bugs/shard/bug-1568521.t                  |  53 ++
887953
 tests/bugs/shard/bug-shard-discard.t            |  19 +-
887953
 tests/bugs/shard/shard-inode-refcount-test.t    |   5 +-
887953
 tests/bugs/shard/unlinks-and-renames.t          | 123 ++--
887953
 xlators/features/shard/src/shard-messages.h     |  18 +-
887953
 xlators/features/shard/src/shard.c              | 816 +++++++++++++++++++-----
887953
 xlators/features/shard/src/shard.h              |  19 +-
887953
 xlators/mgmt/glusterd/src/glusterd-volume-set.c |   5 +
887953
 10 files changed, 829 insertions(+), 260 deletions(-)
887953
 create mode 100644 tests/bugs/shard/bug-1568521.t
887953
887953
diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h
887953
index 8e218cb..699e73e 100644
887953
--- a/libglusterfs/src/globals.h
887953
+++ b/libglusterfs/src/globals.h
887953
@@ -109,6 +109,7 @@
887953
 
887953
 #define GD_OP_VERSION_3_13_2   31302 /* Op-version for GlusterFS 3.13.2 */
887953
 
887953
+#define GD_OP_VERSION_4_2_0    40200 /* Op-version for GlusterFs  4.2.0 */
887953
 
887953
 /* Downstream only change */
887953
 #define GD_OP_VERSION_3_11_2   31102 /* Op-version for RHGS 3.3.1-async */
887953
diff --git a/tests/bugs/shard/bug-1568521-EEXIST.t b/tests/bugs/shard/bug-1568521-EEXIST.t
887953
index e4c3d41..7de400d 100644
887953
--- a/tests/bugs/shard/bug-1568521-EEXIST.t
887953
+++ b/tests/bugs/shard/bug-1568521-EEXIST.t
887953
@@ -5,6 +5,12 @@
887953
 
887953
 cleanup
887953
 
887953
+function get_file_count {
887953
+    ls $1* | wc -l
887953
+}
887953
+
887953
+FILE_COUNT_TIME=5
887953
+
887953
 TEST glusterd
887953
 TEST pidof glusterd
887953
 TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
887953
@@ -41,10 +47,14 @@ TEST setfattr -n trusted.glusterfs.shard.file-size -v 0x000000000050000000000000
887953
 sleep 2
887953
 
887953
 TEST unlink $M0/dir/file
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_file
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_file
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_file
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_file
887953
+
887953
+TEST ! stat $B0/${V0}0/dir/file
887953
+TEST ! stat $B0/${V0}1/dir/file
887953
+
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_file
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_file
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/$gfid_file
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/$gfid_file
887953
 
887953
 ##############################
887953
 ### Repeat test for rename ###
887953
@@ -71,9 +81,13 @@ TEST setfattr -n trusted.glusterfs.shard.file-size -v 0x000000000050000000000000
887953
 sleep 2
887953
 
887953
 TEST mv -f $M0/src $M0/dir/dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+
887953
+TEST ! stat $B0/${V0}0/src
887953
+TEST ! stat $B0/${V0}1/src
887953
+
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/$gfid_dst
887953
 
887953
 cleanup
887953
diff --git a/tests/bugs/shard/bug-1568521.t b/tests/bugs/shard/bug-1568521.t
887953
new file mode 100644
887953
index 0000000..167fb63
887953
--- /dev/null
887953
+++ b/tests/bugs/shard/bug-1568521.t
887953
@@ -0,0 +1,53 @@
887953
+#!/bin/bash
887953
+
887953
+. $(dirname $0)/../../include.rc
887953
+
887953
+
887953
+function delete_files {
887953
+        local mountpoint=$1;
887953
+        local success=0;
887953
+        local value=$2
887953
+        for i in {1..500}; do
887953
+                unlink $mountpoint/file-$i 2>/dev/null 1>/dev/null
887953
+                if [ $? -eq 0 ]; then
887953
+                        echo $2 >> $B0/output.txt
887953
+                fi
887953
+        done
887953
+        echo $success
887953
+}
887953
+
887953
+cleanup
887953
+
887953
+TEST glusterd
887953
+TEST pidof glusterd
887953
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
887953
+TEST $CLI volume set $V0 features.shard on
887953
+TEST $CLI volume set $V0 shard-block-size 4MB
887953
+TEST $CLI volume start $V0
887953
+
887953
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
887953
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M1
887953
+
887953
+for i in {1..500}; do
887953
+        dd if=/dev/urandom of=$M0/file-$i bs=1M count=2
887953
+done
887953
+
887953
+for i in {1..500}; do
887953
+        stat $M1/file-$i > /dev/null
887953
+done
887953
+
887953
+delete_files $M0 0 &
887953
+delete_files $M1 1 &
887953
+wait
887953
+
887953
+success1=$(grep 0 $B0/output.txt | wc -l);
887953
+success2=$(grep 1 $B0/output.txt | wc -l);
887953
+
887953
+echo "Success1 is $success1";
887953
+echo "Success2 is $success2";
887953
+
887953
+success_total=$((success1 + success2));
887953
+
887953
+EXPECT 500 echo $success_total
887953
+
887953
+cleanup
887953
diff --git a/tests/bugs/shard/bug-shard-discard.t b/tests/bugs/shard/bug-shard-discard.t
887953
index 884d9e7..910ade1 100644
887953
--- a/tests/bugs/shard/bug-shard-discard.t
887953
+++ b/tests/bugs/shard/bug-shard-discard.t
887953
@@ -5,6 +5,12 @@
887953
 
887953
 cleanup
887953
 
887953
+FILE_COUNT_TIME=5
887953
+
887953
+function get_shard_count {
887953
+    ls $1/$2.* | wc -l
887953
+}
887953
+
887953
 TEST glusterd
887953
 TEST pidof glusterd
887953
 TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0..3}
887953
@@ -42,14 +48,11 @@ EXPECT_NOT "1" file_all_zeroes `find $B0 -name $gfid_foo.1`
887953
 
887953
 # Now unlink the file. And ensure that all shards associated with the file are cleaned up
887953
 TEST unlink $M0/foo
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_foo.1
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_foo.1
887953
-#TEST ! stat $B0/${V0}2/.shard/$gfid_foo.1
887953
-#TEST ! stat $B0/${V0}3/.shard/$gfid_foo.1
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_foo.2
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_foo.2
887953
-#TEST ! stat $B0/${V0}2/.shard/$gfid_foo.2
887953
-#TEST ! stat $B0/${V0}3/.shard/$gfid_foo.2
887953
+
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_shard_count $B0/${V0}0/.shard $gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_shard_count $B0/${V0}1/.shard $gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_shard_count $B0/${V0}2/.shard $gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_shard_count $B0/${V0}3/.shard $gfid_foo
887953
 TEST ! stat $M0/foo
887953
 
887953
 #clean up everything
887953
diff --git a/tests/bugs/shard/shard-inode-refcount-test.t b/tests/bugs/shard/shard-inode-refcount-test.t
887953
index c92dc07..087c8ba 100644
887953
--- a/tests/bugs/shard/shard-inode-refcount-test.t
887953
+++ b/tests/bugs/shard/shard-inode-refcount-test.t
887953
@@ -5,6 +5,8 @@
887953
 
887953
 cleanup
887953
 
887953
+SHARD_COUNT_TIME=5
887953
+
887953
 TEST glusterd
887953
 TEST pidof glusterd
887953
 TEST $CLI volume create $V0 $H0:$B0/${V0}0
887953
@@ -18,7 +20,8 @@ TEST dd if=/dev/zero conv=fsync of=$M0/one-plus-five-shards bs=1M count=23
887953
 
887953
 ACTIVE_INODES_BEFORE=$(get_mount_active_size_value $V0)
887953
 TEST rm -f $M0/one-plus-five-shards
887953
-#EXPECT `expr $ACTIVE_INODES_BEFORE - 4` get_mount_active_size_value $V0
887953
+# Expect 5 inodes less. But one inode more than before because .remove_me would be created.
887953
+EXPECT_WITHIN $SHARD_COUNT_TIME `expr $ACTIVE_INODES_BEFORE - 5 + 1` get_mount_active_size_value $V0
887953
 
887953
 EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
887953
 TEST $CLI volume stop $V0
887953
diff --git a/tests/bugs/shard/unlinks-and-renames.t b/tests/bugs/shard/unlinks-and-renames.t
887953
index 997c397..6e5164f 100644
887953
--- a/tests/bugs/shard/unlinks-and-renames.t
887953
+++ b/tests/bugs/shard/unlinks-and-renames.t
887953
@@ -9,6 +9,12 @@ cleanup
887953
 # and rename fops in sharding and make sure they work fine.
887953
 #
887953
 
887953
+FILE_COUNT_TIME=5
887953
+
887953
+function get_file_count {
887953
+    ls $1* | wc -l
887953
+}
887953
+
887953
 #################################################
887953
 ################### UNLINK ######################
887953
 #################################################
887953
@@ -36,13 +42,8 @@ gfid_foo=$(get_gfid_string $M0/dir/foo)
887953
 TEST unlink $M0/dir/foo
887953
 TEST stat $B0/${V0}0/.shard/.remove_me
887953
 TEST stat $B0/${V0}1/.shard/.remove_me
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
-
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
 
887953
 ##################################################
887953
 ##### Unlink of a sharded file without holes #####
887953
@@ -56,20 +57,14 @@ TEST stat $B0/${V0}1/.shard/$gfid_new.1
887953
 TEST stat $B0/${V0}0/.shard/$gfid_new.2
887953
 TEST stat $B0/${V0}1/.shard/$gfid_new.2
887953
 TEST unlink $M0/dir/new
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_new.1
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_new.1
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_new.2
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_new.2
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/$gfid_new
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/$gfid_new
887953
 TEST ! stat $M0/dir/new
887953
 TEST ! stat $B0/${V0}0/dir/new
887953
 TEST ! stat $B0/${V0}1/dir/new
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_new
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_new
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_new
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_new
887953
 
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_new
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_new
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_new
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_new
887953
 #######################################
887953
 ##### Unlink with /.shard present #####
887953
 #######################################
887953
@@ -83,13 +78,8 @@ TEST unlink $M0/dir/foo
887953
 TEST ! stat $B0/${V0}0/dir/foo
887953
 TEST ! stat $B0/${V0}1/dir/foo
887953
 TEST ! stat $M0/dir/foo
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
-
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
 
887953
 #############################################################
887953
 ##### Unlink of a file with only one block (the zeroth) #####
887953
@@ -102,13 +92,9 @@ TEST unlink $M0/dir/foo
887953
 TEST ! stat $B0/${V0}0/dir/foo
887953
 TEST ! stat $B0/${V0}1/dir/foo
887953
 TEST ! stat $M0/dir/foo
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
 
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000100000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_foo
887953
-EXPECT "0000000000100000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_foo
887953
 ####################################################
887953
 ##### Unlink of a sharded file with hard-links #####
887953
 ####################################################
887953
@@ -137,22 +123,15 @@ TEST stat $B0/${V0}0/link
887953
 TEST stat $B0/${V0}1/link
887953
 # Now delete the last link.
887953
 TEST unlink $M0/link
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_original
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_original
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_original
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_original
887953
 # Ensure that the shards are all cleaned up.
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_original.1
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_original.1
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_original.2
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_original.2
887953
-#TEST ! stat $M0/link
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/$gfid_original
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/$gfid_original
887953
+TEST ! stat $M0/link
887953
 TEST ! stat $B0/${V0}0/link
887953
 TEST ! stat $B0/${V0}1/link
887953
 
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_original
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_original
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_original
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_original
887953
-
887953
 EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
887953
 TEST $CLI volume stop $V0
887953
 TEST $CLI volume delete $V0
887953
@@ -190,13 +169,8 @@ TEST ! stat $B0/${V0}0/dir/src
887953
 TEST ! stat $B0/${V0}1/dir/src
887953
 TEST   stat $B0/${V0}0/dir/dst
887953
 TEST   stat $B0/${V0}1/dir/dst
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 
887953
 ##################################################
887953
 ##### Rename to a sharded file without holes #####
887953
@@ -212,23 +186,16 @@ TEST stat $B0/${V0}1/.shard/$gfid_dst.1
887953
 TEST stat $B0/${V0}0/.shard/$gfid_dst.2
887953
 TEST stat $B0/${V0}1/.shard/$gfid_dst.2
887953
 TEST mv -f $M0/dir/src $M0/dir/dst
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_dst.1
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_dst.1
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_dst.2
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_dst.2
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/$gfid_dst
887953
 TEST ! stat $M0/dir/src
887953
 TEST   stat $M0/dir/dst
887953
 TEST ! stat $B0/${V0}0/dir/src
887953
 TEST ! stat $B0/${V0}1/dir/src
887953
 TEST   stat $B0/${V0}0/dir/dst
887953
 TEST   stat $B0/${V0}1/dir/dst
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 
887953
 ###################################################
887953
 ##### Rename of dst file with /.shard present #####
887953
@@ -245,13 +212,8 @@ TEST ! stat $B0/${V0}0/dir/src
887953
 TEST ! stat $B0/${V0}1/dir/src
887953
 TEST   stat $B0/${V0}0/dir/dst
887953
 TEST   stat $B0/${V0}1/dir/dst
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000500000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 
887953
 ###############################################################
887953
 ##### Rename of dst file with only one block (the zeroth) #####
887953
@@ -268,13 +230,8 @@ TEST ! stat $B0/${V0}0/dir/src
887953
 TEST ! stat $B0/${V0}1/dir/src
887953
 TEST   stat $B0/${V0}0/dir/dst
887953
 TEST   stat $B0/${V0}1/dir/dst
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000100000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000100000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 
887953
 ########################################################
887953
 ##### Rename to a dst sharded file with hard-links #####
887953
@@ -307,20 +264,18 @@ TEST ! stat $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 TEST touch $M0/dir/src2
887953
 TEST mv -f $M0/dir/src2 $M0/link
887953
 # Ensure that the shards are all cleaned up.
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_dst.1
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_dst.1
887953
-#TEST ! stat $B0/${V0}0/.shard/$gfid_dst.2
887953
-#TEST ! stat $B0/${V0}1/.shard/$gfid_dst.2
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/$gfid_dst
887953
+TEST ! stat $B0/${V0}0/.shard/$gfid_dst.1
887953
+TEST ! stat $B0/${V0}1/.shard/$gfid_dst.1
887953
+TEST ! stat $B0/${V0}0/.shard/$gfid_dst.2
887953
+TEST ! stat $B0/${V0}1/.shard/$gfid_dst.2
887953
 TEST ! stat $M0/dir/src2
887953
 TEST ! stat $B0/${V0}0/dir/src2
887953
 TEST ! stat $B0/${V0}1/dir/src2
887953
-TEST stat $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-TEST stat $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000400000" get_hex_xattr trusted.glusterfs.shard.block-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}0/.shard/.remove_me/$gfid_dst
887953
-EXPECT "0000000000900000000000000000000000000000000000000000000000000000" get_hex_xattr trusted.glusterfs.shard.file-size $B0/${V0}1/.shard/.remove_me/$gfid_dst
887953
 # Rename with non-existent dst and a sharded src
887953
 TEST touch $M0/dir/src
887953
 TEST dd if=/dev/zero of=$M0/dir/src bs=1024 count=9216
887953
diff --git a/xlators/features/shard/src/shard-messages.h b/xlators/features/shard/src/shard-messages.h
887953
index 0267f8a..bc04e5e 100644
887953
--- a/xlators/features/shard/src/shard-messages.h
887953
+++ b/xlators/features/shard/src/shard-messages.h
887953
@@ -40,7 +40,7 @@
887953
  */
887953
 
887953
 #define GLFS_COMP_BASE_SHARD      GLFS_MSGID_COMP_SHARD
887953
-#define GLFS_NUM_MESSAGES         20
887953
+#define GLFS_NUM_MESSAGES         22
887953
 #define GLFS_MSGID_END          (GLFS_COMP_BASE_SHARD + GLFS_NUM_MESSAGES + 1)
887953
 
887953
 #define glfs_msg_start_x GLFS_COMP_BASE_SHARD, "Invalid: Start of messages"
887953
@@ -58,7 +58,7 @@
887953
  * @diagnosis
887953
  * @recommendedaction
887953
  */
887953
-#define SHARD_MSG_DICT_SET_FAILED                     (GLFS_COMP_BASE_SHARD + 2)
887953
+#define SHARD_MSG_DICT_OP_FAILED                     (GLFS_COMP_BASE_SHARD + 2)
887953
 
887953
 
887953
 /*!
887953
@@ -194,5 +194,19 @@
887953
 */
887953
 #define SHARD_MSG_FOP_FAILED                         (GLFS_COMP_BASE_SHARD + 20)
887953
 
887953
+/*!
887953
+ * @messageid 133021
887953
+ * @diagnosis
887953
+ * @recommendedaction
887953
+*/
887953
+#define SHARD_MSG_SHARDS_DELETION_FAILED             (GLFS_COMP_BASE_SHARD + 21)
887953
+
887953
+/*!
887953
+ * @messageid 133022
887953
+ * @diagnosis
887953
+ * @recommendedaction
887953
+*/
887953
+#define SHARD_MSG_SHARDS_DELETION_COMPLETED          (GLFS_COMP_BASE_SHARD + 22)
887953
+
887953
 #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
887953
 #endif /* !_SHARD_MESSAGES_H_ */
887953
diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c
887953
index 492341c..2faf711 100644
887953
--- a/xlators/features/shard/src/shard.c
887953
+++ b/xlators/features/shard/src/shard.c
887953
@@ -677,7 +677,8 @@ __shard_update_shards_inode_list (inode_t *linked_inode, xlator_t *this,
887953
                          * keep it alive by holding a ref on it.
887953
                          */
887953
                         inode_ref (linked_inode);
887953
-                        gf_uuid_copy (ctx->base_gfid, base_inode->gfid);
887953
+                        if (base_inode)
887953
+                                gf_uuid_copy (ctx->base_gfid, base_inode->gfid);
887953
                         ctx->block_num = block_num;
887953
                         list_add_tail (&ctx->ilist, &priv->ilist_head);
887953
                         priv->inode_count++;
887953
@@ -738,7 +739,8 @@ __shard_update_shards_inode_list (inode_t *linked_inode, xlator_t *this,
887953
                          * keep it alive by holding a ref on it.
887953
                          */
887953
                         inode_ref (linked_inode);
887953
-                        gf_uuid_copy (ctx->base_gfid, base_inode->gfid);
887953
+                        if (base_inode)
887953
+                                gf_uuid_copy (ctx->base_gfid, base_inode->gfid);
887953
                         ctx->block_num = block_num;
887953
                         ctx->base_inode = base_inode;
887953
                         list_add_tail (&ctx->ilist, &priv->ilist_head);
887953
@@ -977,6 +979,7 @@ shard_common_resolve_shards (call_frame_t *frame, xlator_t *this,
887953
         int                   i              = -1;
887953
         uint32_t              shard_idx_iter = 0;
887953
         char                  path[PATH_MAX] = {0,};
887953
+        uuid_t                gfid           = {0,};
887953
         inode_t              *inode          = NULL;
887953
         inode_t              *res_inode      = NULL;
887953
         inode_t              *fsync_inode    = NULL;
887953
@@ -988,6 +991,10 @@ shard_common_resolve_shards (call_frame_t *frame, xlator_t *this,
887953
         local->call_count = 0;
887953
         shard_idx_iter = local->first_block;
887953
         res_inode = local->resolver_base_inode;
887953
+        if (res_inode)
887953
+                gf_uuid_copy (gfid, res_inode->gfid);
887953
+        else
887953
+                gf_uuid_copy (gfid, local->base_gfid);
887953
 
887953
         if ((local->op_ret < 0) || (local->resolve_not))
887953
                 goto out;
887953
@@ -1000,7 +1007,7 @@ shard_common_resolve_shards (call_frame_t *frame, xlator_t *this,
887953
                         continue;
887953
                 }
887953
 
887953
-                shard_make_block_abspath (shard_idx_iter, res_inode->gfid, path,
887953
+                shard_make_block_abspath (shard_idx_iter, gfid, path,
887953
                                           sizeof(path));
887953
 
887953
                 inode = NULL;
887953
@@ -1147,7 +1154,7 @@ shard_update_file_size (call_frame_t *frame, xlator_t *this, fd_t *fd,
887953
         ret = dict_set_bin (xattr_req, GF_XATTR_SHARD_FILE_SIZE, size_attr,
887953
                             8 * 4);
887953
         if (ret) {
887953
-                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_SET_FAILED,
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_OP_FAILED,
887953
                         "Failed to set key %s into dict. gfid=%s",
887953
                         GF_XATTR_SHARD_FILE_SIZE, uuid_utoa (inode->gfid));
887953
                 GF_FREE (size_attr);
887953
@@ -1376,7 +1383,7 @@ shard_lookup_internal_dir (call_frame_t *frame, xlator_t *this,
887953
 
887953
         ret = dict_set_bin (xattr_req, "gfid-req", *gfid, 16);
887953
         if (ret) {
887953
-                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_SET_FAILED,
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_OP_FAILED,
887953
                         "Failed to set gfid of %s into dict",
887953
                         shard_internal_dir_string (type));
887953
                 local->op_ret = -1;
887953
@@ -1431,10 +1438,49 @@ shard_inode_ctx_update (inode_t *inode, xlator_t *this, dict_t *xdata,
887953
 }
887953
 
887953
 int
887953
+shard_delete_shards (void *opaque);
887953
+
887953
+int
887953
+shard_delete_shards_cbk (int ret, call_frame_t *frame, void *data);
887953
+
887953
+int
887953
+shard_start_background_deletion (xlator_t *this)
887953
+{
887953
+        int              ret           = 0;
887953
+        call_frame_t    *cleanup_frame = NULL;
887953
+
887953
+        cleanup_frame = create_frame (this, this->ctx->pool);
887953
+        if (!cleanup_frame) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
887953
+                        SHARD_MSG_MEMALLOC_FAILED, "Failed to create "
887953
+                        "new frame to delete shards");
887953
+                return -ENOMEM;
887953
+        }
887953
+
887953
+        ret = synctask_new (this->ctx->env, shard_delete_shards,
887953
+                            shard_delete_shards_cbk, cleanup_frame,
887953
+                            cleanup_frame);
887953
+        if (ret < 0) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, errno,
887953
+                        SHARD_MSG_SHARDS_DELETION_FAILED,
887953
+                        "failed to create task to do background "
887953
+                        "cleanup of shards");
887953
+                STACK_DESTROY (cleanup_frame->root);
887953
+        }
887953
+        return ret;
887953
+}
887953
+
887953
+int
887953
 shard_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                   int32_t op_ret, int32_t op_errno, inode_t *inode,
887953
                   struct iatt *buf, dict_t *xdata, struct iatt *postparent)
887953
 {
887953
+        int             ret             = 0;
887953
+        shard_priv_t   *priv            = NULL;
887953
+        gf_boolean_t    i_start_cleanup = _gf_false;
887953
+
887953
+        priv = this->private;
887953
+
887953
         if (op_ret < 0)
887953
                 goto unwind;
887953
 
887953
@@ -1460,6 +1506,25 @@ shard_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
 
887953
         (void) shard_inode_ctx_update (inode, this, xdata, buf);
887953
 
887953
+        LOCK (&priv->lock);
887953
+        {
887953
+                if (priv->first_lookup == SHARD_FIRST_LOOKUP_PENDING) {
887953
+                        priv->first_lookup = SHARD_FIRST_LOOKUP_IN_PROGRESS;
887953
+                        i_start_cleanup = _gf_true;
887953
+                }
887953
+        }
887953
+        UNLOCK (&priv->lock);
887953
+
887953
+        if (i_start_cleanup) {
887953
+                ret = shard_start_background_deletion (this);
887953
+                if (ret) {
887953
+                        LOCK (&priv->lock);
887953
+                        {
887953
+                                priv->first_lookup = SHARD_FIRST_LOOKUP_PENDING;
887953
+                        }
887953
+                        UNLOCK (&priv->lock);
887953
+                }
887953
+        }
887953
 unwind:
887953
         SHARD_STACK_UNWIND (lookup, frame, op_ret, op_errno, inode, buf,
887953
                             xdata, postparent);
887953
@@ -1475,6 +1540,7 @@ shard_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc,
887953
         uint64_t        block_size = 0;
887953
         shard_local_t  *local      = NULL;
887953
 
887953
+        this->itable = loc->inode->table;
887953
         if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
887953
                 SHARD_ENTRY_FOP_CHECK (loc, op_errno, err);
887953
         }
887953
@@ -1496,7 +1562,7 @@ shard_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc,
887953
                                        GF_XATTR_SHARD_BLOCK_SIZE, 0);
887953
                 if (ret) {
887953
                         gf_msg (this->name, GF_LOG_WARNING, 0,
887953
-                                SHARD_MSG_DICT_SET_FAILED, "Failed to set dict"
887953
+                                SHARD_MSG_DICT_OP_FAILED, "Failed to set dict"
887953
                                 " value: key:%s for path %s",
887953
                                 GF_XATTR_SHARD_BLOCK_SIZE, loc->path);
887953
                         goto err;
887953
@@ -1508,7 +1574,7 @@ shard_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc,
887953
                                        GF_XATTR_SHARD_FILE_SIZE, 8 * 4);
887953
                 if (ret) {
887953
                         gf_msg (this->name, GF_LOG_WARNING, 0,
887953
-                                SHARD_MSG_DICT_SET_FAILED,
887953
+                                SHARD_MSG_DICT_OP_FAILED,
887953
                                 "Failed to set dict value: key:%s for path %s.",
887953
                                 GF_XATTR_SHARD_FILE_SIZE, loc->path);
887953
                         goto err;
887953
@@ -1901,12 +1967,6 @@ shard_truncate_last_shard (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
         return 0;
887953
 }
887953
 
887953
-int
887953
-shard_unlink_shards_do_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
-                            int32_t op_ret, int32_t op_errno,
887953
-                            struct iatt *preparent, struct iatt *postparent,
887953
-                            dict_t *xdata);
887953
-
887953
 void
887953
 shard_unlink_block_inode (shard_local_t *local, int shard_block_num);
887953
 
887953
@@ -1941,17 +2001,17 @@ done:
887953
 int
887953
 shard_truncate_htol (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
 {
887953
-        int i = 1;
887953
-        int ret = -1;
887953
-        int call_count = 0;
887953
-        uint32_t cur_block = 0;
887953
-        uint32_t last_block = 0;
887953
-        char path[PATH_MAX] = {0,};
887953
-        char *bname = NULL;
887953
-        loc_t loc = {0,};
887953
-        gf_boolean_t wind_failed = _gf_false;
887953
-        shard_local_t *local = NULL;
887953
-        shard_priv_t *priv = NULL;
887953
+        int             i              = 1;
887953
+        int             ret            = -1;
887953
+        int             call_count     = 0;
887953
+        uint32_t        cur_block      = 0;
887953
+        uint32_t        last_block     = 0;
887953
+        char            path[PATH_MAX] = {0,};
887953
+        char           *bname          = NULL;
887953
+        loc_t           loc            = {0,};
887953
+        gf_boolean_t    wind_failed    = _gf_false;
887953
+        shard_local_t  *local          = NULL;
887953
+        shard_priv_t   *priv           = NULL;
887953
 
887953
         local = frame->local;
887953
         priv = this->private;
887953
@@ -2086,6 +2146,7 @@ shard_link_block_inode (shard_local_t *local, int block_num, inode_t *inode,
887953
 {
887953
         int             list_index       = 0;
887953
         char            block_bname[256] = {0,};
887953
+        uuid_t          gfid             = {0,};
887953
         inode_t        *linked_inode     = NULL;
887953
         xlator_t       *this             = NULL;
887953
         inode_t        *fsync_inode      = NULL;
887953
@@ -2093,9 +2154,12 @@ shard_link_block_inode (shard_local_t *local, int block_num, inode_t *inode,
887953
 
887953
         this = THIS;
887953
         priv = this->private;
887953
+        if (local->loc.inode)
887953
+                gf_uuid_copy (gfid, local->loc.inode->gfid);
887953
+        else
887953
+                gf_uuid_copy (gfid, local->base_gfid);
887953
 
887953
-        shard_make_block_bname (block_num, (local->loc.inode)->gfid,
887953
-                                block_bname, sizeof (block_bname));
887953
+        shard_make_block_bname (block_num, gfid, block_bname, sizeof (block_bname));
887953
 
887953
         shard_inode_ctx_set (inode, this, buf, 0, SHARD_LOOKUP_MASK);
887953
         linked_inode = inode_link (inode, priv->dot_shard_inode, block_bname,
887953
@@ -2125,9 +2189,14 @@ shard_common_lookup_shards_cbk (call_frame_t *frame, void *cookie,
887953
 {
887953
         int             call_count      = 0;
887953
         int             shard_block_num = (long) cookie;
887953
+        uuid_t          gfid            = {0,};
887953
         shard_local_t  *local           = NULL;
887953
 
887953
         local = frame->local;
887953
+        if (local->resolver_base_inode)
887953
+                gf_uuid_copy (gfid, local->resolver_base_inode->gfid);
887953
+        else
887953
+                gf_uuid_copy (gfid, local->base_gfid);
887953
 
887953
         if (op_ret < 0) {
887953
                 /* Ignore absence of shards in the backend in truncate fop. */
887953
@@ -2162,9 +2231,7 @@ shard_common_lookup_shards_cbk (call_frame_t *frame, void *cookie,
887953
                 gf_msg (this->name, GF_LOG_ERROR, op_errno,
887953
                         SHARD_MSG_LOOKUP_SHARD_FAILED, "Lookup on shard %d "
887953
                         "failed. Base file gfid = %s", shard_block_num,
887953
-                        (local->fop == GF_FOP_RENAME) ?
887953
-                        uuid_utoa (local->loc2.inode->gfid)
887953
-                        : uuid_utoa (local->loc.inode->gfid));
887953
+                        uuid_utoa (gfid));
887953
                 local->op_ret = op_ret;
887953
                 local->op_errno = op_errno;
887953
                 goto done;
887953
@@ -2173,25 +2240,18 @@ shard_common_lookup_shards_cbk (call_frame_t *frame, void *cookie,
887953
         shard_link_block_inode (local, shard_block_num, inode, buf);
887953
 
887953
 done:
887953
-        call_count = shard_call_count_return (frame);
887953
         if (local->lookup_shards_barriered) {
887953
                 syncbarrier_wake (&local->barrier);
887953
                 return 0;
887953
         } else {
887953
+                call_count = shard_call_count_return (frame);
887953
                 if (call_count == 0) {
887953
                         if (!local->first_lookup_done)
887953
                                 local->first_lookup_done = _gf_true;
887953
-                        if (local->op_ret < 0)
887953
-                                goto unwind;
887953
-                        else
887953
-                                local->pls_fop_handler (frame, this);
887953
+                        local->pls_fop_handler (frame, this);
887953
                 }
887953
         }
887953
         return 0;
887953
-
887953
-unwind:
887953
-        local->pls_fop_handler (frame, this);
887953
-        return 0;
887953
 }
887953
 
887953
 dict_t*
887953
@@ -2237,6 +2297,7 @@ shard_common_lookup_shards (call_frame_t *frame, xlator_t *this, inode_t *inode,
887953
         int            last_block     = 0;
887953
         char           path[PATH_MAX] = {0,};
887953
         char          *bname          = NULL;
887953
+        uuid_t         gfid           = {0,};
887953
         loc_t          loc            = {0,};
887953
         shard_local_t *local          = NULL;
887953
         shard_priv_t  *priv           = NULL;
887953
@@ -2252,6 +2313,11 @@ shard_common_lookup_shards (call_frame_t *frame, xlator_t *this, inode_t *inode,
887953
         if (local->lookup_shards_barriered)
887953
                 local->barrier.waitfor = local->call_count;
887953
 
887953
+        if (inode)
887953
+                gf_uuid_copy (gfid, inode->gfid);
887953
+        else
887953
+                gf_uuid_copy (gfid, local->base_gfid);
887953
+
887953
         while (shard_idx_iter <= last_block) {
887953
                 if (local->inode_list[i]) {
887953
                         i++;
887953
@@ -2267,7 +2333,7 @@ shard_common_lookup_shards (call_frame_t *frame, xlator_t *this, inode_t *inode,
887953
                         goto next;
887953
                 }
887953
 
887953
-                shard_make_block_abspath (shard_idx_iter, inode->gfid, path,
887953
+                shard_make_block_abspath (shard_idx_iter, gfid, path,
887953
                                           sizeof(path));
887953
 
887953
                 bname = strrchr (path, '/') + 1;
887953
@@ -2279,7 +2345,7 @@ shard_common_lookup_shards (call_frame_t *frame, xlator_t *this, inode_t *inode,
887953
                         gf_msg (this->name, GF_LOG_ERROR, 0,
887953
                                 SHARD_MSG_INODE_PATH_FAILED, "Inode path failed"
887953
                                 " on %s, base file gfid = %s", bname,
887953
-                                uuid_utoa (inode->gfid));
887953
+                                uuid_utoa (gfid));
887953
                         local->op_ret = -1;
887953
                         local->op_errno = ENOMEM;
887953
                         loc_wipe (&loc;;
887953
@@ -2322,8 +2388,10 @@ next:
887953
                 if (!--call_count)
887953
                         break;
887953
         }
887953
-        if (local->lookup_shards_barriered)
887953
+        if (local->lookup_shards_barriered) {
887953
                 syncbarrier_wait (&local->barrier, count);
887953
+                local->pls_fop_handler (frame, this);
887953
+        }
887953
         return 0;
887953
 }
887953
 
887953
@@ -2779,8 +2847,9 @@ shard_post_lookup_shards_unlink_handler (call_frame_t *frame, xlator_t *this)
887953
         local = frame->local;
887953
 
887953
         if ((local->op_ret < 0) && (local->op_errno != ENOENT)) {
887953
-                shard_common_failure_unwind (local->fop, frame, local->op_ret,
887953
-                                             local->op_errno);
887953
+                gf_msg (this->name, GF_LOG_ERROR, local->op_errno,
887953
+                        SHARD_MSG_FOP_FAILED, "failed to delete shards of %s",
887953
+                        uuid_utoa (local->resolver_base_inode->gfid));
887953
                 return 0;
887953
         }
887953
         local->op_ret = 0;
887953
@@ -2791,41 +2860,12 @@ shard_post_lookup_shards_unlink_handler (call_frame_t *frame, xlator_t *this)
887953
 }
887953
 
887953
 int
887953
-shard_rename_cbk (call_frame_t *frame, xlator_t *this);
887953
-
887953
-int32_t
887953
-shard_unlink_cbk (call_frame_t *frame, xlator_t *this);
887953
-
887953
-int
887953
 shard_post_resolve_unlink_handler (call_frame_t *frame, xlator_t *this)
887953
 {
887953
         shard_local_t *local = NULL;
887953
 
887953
         local = frame->local;
887953
-
887953
-        if (local->op_ret < 0) {
887953
-                if (local->op_errno == ENOENT) {
887953
-                        /* If lookup on /.shard fails with ENOENT, it probably
887953
-                         * means that the file is being unlinked before it
887953
-                         * could grow beyond its first block. In this case,
887953
-                         * unlink boils down to unlinking the base file and
887953
-                         * unwinding the call.
887953
-                         */
887953
-                        local->op_ret = 0;
887953
-                        local->first_block = local->last_block = 0;
887953
-                        local->num_blocks = 1;
887953
-                        if (local->fop == GF_FOP_UNLINK)
887953
-                                shard_unlink_cbk (frame, this);
887953
-                        else
887953
-                                shard_rename_cbk (frame, this);
887953
-                        return 0;
887953
-                } else {
887953
-                        shard_common_failure_unwind (local->fop, frame,
887953
-                                                     local->op_ret,
887953
-                                                     local->op_errno);
887953
-                        return 0;
887953
-                }
887953
-        }
887953
+        local->lookup_shards_barriered = _gf_true;
887953
 
887953
         if (!local->call_count)
887953
                 shard_unlink_shards_do (frame, this,
887953
@@ -2841,6 +2881,7 @@ void
887953
 shard_unlink_block_inode (shard_local_t *local, int shard_block_num)
887953
 {
887953
         char                  block_bname[256]  = {0,};
887953
+        uuid_t                gfid              = {0,};
887953
         inode_t              *inode             = NULL;
887953
         inode_t              *base_inode        = NULL;
887953
         xlator_t             *this              = NULL;
887953
@@ -2854,12 +2895,17 @@ shard_unlink_block_inode (shard_local_t *local, int shard_block_num)
887953
 
887953
         inode = local->inode_list[shard_block_num - local->first_block];
887953
         base_inode = local->resolver_base_inode;
887953
+        if (base_inode)
887953
+                gf_uuid_copy (gfid, base_inode->gfid);
887953
+        else
887953
+                gf_uuid_copy (gfid, local->base_gfid);
887953
 
887953
-        shard_make_block_bname (shard_block_num, (local->loc.inode)->gfid,
887953
+        shard_make_block_bname (shard_block_num, gfid,
887953
                                 block_bname, sizeof (block_bname));
887953
 
887953
         LOCK(&priv->lock);
887953
-        LOCK(&base_inode->lock);
887953
+        if (base_inode)
887953
+                LOCK(&base_inode->lock);
887953
         LOCK(&inode->lock);
887953
         {
887953
                 __shard_inode_ctx_get (inode, this, &ctx;;
887953
@@ -2870,14 +2916,18 @@ shard_unlink_block_inode (shard_local_t *local, int shard_block_num)
887953
                         unlink_unref_forget = _gf_true;
887953
                 }
887953
                 if (ctx->fsync_needed) {
887953
-                        inode_unref (base_inode);
887953
+                        if (base_inode)
887953
+                                inode_unref (base_inode);
887953
                         list_del_init (&ctx->to_fsync_list);
887953
-                        __shard_inode_ctx_get (base_inode, this, &base_ictx);
887953
-                        base_ictx->fsync_count--;
887953
+                        if (base_inode) {
887953
+                                __shard_inode_ctx_get (base_inode, this, &base_ictx);
887953
+                                base_ictx->fsync_count--;
887953
+                        }
887953
                 }
887953
         }
887953
         UNLOCK(&inode->lock);
887953
-        UNLOCK(&base_inode->lock);
887953
+        if (base_inode)
887953
+                UNLOCK(&base_inode->lock);
887953
         if (unlink_unref_forget) {
887953
                 inode_unlink (inode, priv->dot_shard_inode, block_bname);
887953
                 inode_unref (inode);
887953
@@ -2887,7 +2937,18 @@ shard_unlink_block_inode (shard_local_t *local, int shard_block_num)
887953
 }
887953
 
887953
 int
887953
-shard_rename_cbk (call_frame_t *frame, xlator_t *this);
887953
+shard_rename_cbk (call_frame_t *frame, xlator_t *this)
887953
+{
887953
+        shard_local_t *local = NULL;
887953
+
887953
+        local = frame->local;
887953
+
887953
+        SHARD_STACK_UNWIND (rename, frame, local->op_ret, local->op_errno,
887953
+                            &local->prebuf, &local->preoldparent,
887953
+                            &local->postoldparent, &local->prenewparent,
887953
+                            &local->postnewparent, local->xattr_rsp);
887953
+        return 0;
887953
+}
887953
 
887953
 int32_t
887953
 shard_unlink_cbk (call_frame_t *frame, xlator_t *this)
887953
@@ -2906,7 +2967,6 @@ shard_unlink_shards_do_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                             struct iatt *preparent, struct iatt *postparent,
887953
                             dict_t *xdata)
887953
 {
887953
-        int            call_count      = 0;
887953
         int            shard_block_num = (long) cookie;
887953
         shard_local_t *local           = NULL;
887953
 
887953
@@ -2919,22 +2979,8 @@ shard_unlink_shards_do_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
         }
887953
 
887953
         shard_unlink_block_inode (local, shard_block_num);
887953
-
887953
 done:
887953
-        call_count = shard_call_count_return (frame);
887953
-        if (local->unlink_shards_barriered) {
887953
-                syncbarrier_wake (&local->barrier);
887953
-        } else {
887953
-
887953
-                if (call_count == 0) {
887953
-                        SHARD_UNSET_ROOT_FS_ID (frame, local);
887953
-
887953
-                        if (local->fop == GF_FOP_UNLINK)
887953
-                                shard_unlink_cbk (frame, this);
887953
-                        else if (local->fop == GF_FOP_RENAME)
887953
-                                shard_rename_cbk (frame, this);
887953
-                }
887953
-        }
887953
+        syncbarrier_wake (&local->barrier);
887953
         return 0;
887953
 }
887953
 
887953
@@ -2944,11 +2990,11 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
         int               i              = 0;
887953
         int               ret            = -1;
887953
         int               count          = 0;
887953
-        int               call_count     = 0;
887953
-        uint32_t          last_block     = 0;
887953
         uint32_t          cur_block      = 0;
887953
+        uint32_t          cur_block_idx  = 0;/*this is idx into inode_list[] array */
887953
         char             *bname          = NULL;
887953
         char              path[PATH_MAX] = {0,};
887953
+        uuid_t           gfid            = {0,};
887953
         loc_t             loc            = {0,};
887953
         gf_boolean_t      wind_failed    = _gf_false;
887953
         shard_local_t    *local          = NULL;
887953
@@ -2957,16 +3003,12 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
         priv = this->private;
887953
         local = frame->local;
887953
 
887953
-        /* local->num_blocks includes the base file block. This function only
887953
-         * deletes the shards under /.shard. So subtract num_blocks by 1.
887953
-         */
887953
-        local->call_count = call_count = local->num_blocks - 1;
887953
-        last_block = local->last_block;
887953
+        if (inode)
887953
+                gf_uuid_copy (gfid, inode->gfid);
887953
+        else
887953
+                gf_uuid_copy (gfid, local->base_gfid);
887953
 
887953
-        /* Ignore the inode associated with the base file and start counting
887953
-         * from 1.
887953
-         */
887953
-        for (i = 1; i < local->num_blocks; i++) {
887953
+        for (i = 0; i < local->num_blocks; i++) {
887953
                 if (!local->inode_list[i])
887953
                         continue;
887953
                 count++;
887953
@@ -2975,35 +3017,21 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
         if (!count) {
887953
                 /* callcount = 0 implies that all of the shards that need to be
887953
                  * unlinked are non-existent (in other words the file is full of
887953
-                 * holes). So shard xlator can simply return the fop to its
887953
-                 * parent now.
887953
+                 * holes).
887953
                  */
887953
                 gf_msg_debug (this->name, 0, "All shards that need to be "
887953
                               "unlinked are non-existent: %s",
887953
-                              uuid_utoa (inode->gfid));
887953
-                local->num_blocks = 1;
887953
-                if (local->fop == GF_FOP_UNLINK) {
887953
-                        shard_unlink_cbk (frame, this);
887953
-                } else if (local->fop == GF_FOP_RENAME) {
887953
-                        gf_msg_debug (this->name, 0, "Resuming rename()");
887953
-                        shard_rename_cbk (frame, this);
887953
-                }
887953
+                              uuid_utoa (gfid));
887953
                 return 0;
887953
         }
887953
 
887953
-        local->call_count = call_count = count;
887953
-        cur_block = 1;
887953
         SHARD_SET_ROOT_FS_ID (frame, local);
887953
-        if (local->unlink_shards_barriered)
887953
-                local->barrier.waitfor = count;
887953
+        local->barrier.waitfor = count;
887953
+        cur_block = cur_block_idx + local->first_block;
887953
 
887953
-        /* Ignore the base file and start iterating from the first block shard.
887953
-         */
887953
-        while (cur_block <= last_block) {
887953
-                if (!local->inode_list[cur_block]) {
887953
-                        cur_block++;
887953
-                        continue;
887953
-                }
887953
+        while (cur_block_idx < local->num_blocks) {
887953
+                if (!local->inode_list[cur_block_idx])
887953
+                        goto next;
887953
 
887953
                 if (wind_failed) {
887953
                         shard_unlink_shards_do_cbk (frame,
887953
@@ -3013,8 +3041,7 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
                         goto next;
887953
                 }
887953
 
887953
-                shard_make_block_abspath (cur_block, inode->gfid, path,
887953
-                                          sizeof (path));
887953
+                shard_make_block_abspath (cur_block, gfid, path, sizeof (path));
887953
                 bname = strrchr (path, '/') + 1;
887953
                 loc.parent = inode_ref (priv->dot_shard_inode);
887953
                 ret = inode_path (loc.parent, bname, (char **) &(loc.path));
887953
@@ -3022,7 +3049,7 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
                         gf_msg (this->name, GF_LOG_ERROR, 0,
887953
                                 SHARD_MSG_INODE_PATH_FAILED, "Inode path failed"
887953
                                 " on %s, base file gfid = %s", bname,
887953
-                                uuid_utoa (inode->gfid));
887953
+                                uuid_utoa (gfid));
887953
                         local->op_ret = -1;
887953
                         local->op_errno = ENOMEM;
887953
                         loc_wipe (&loc;;
887953
@@ -3037,26 +3064,505 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode)
887953
                 loc.name = strrchr (loc.path, '/');
887953
                 if (loc.name)
887953
                         loc.name++;
887953
-                loc.inode = inode_ref (local->inode_list[cur_block]);
887953
+                loc.inode = inode_ref (local->inode_list[cur_block_idx]);
887953
 
887953
                 STACK_WIND_COOKIE (frame, shard_unlink_shards_do_cbk,
887953
                                    (void *) (long) cur_block, FIRST_CHILD(this),
887953
                                    FIRST_CHILD (this)->fops->unlink, &loc,
887953
                                    local->xflag, local->xattr_req);
887953
                 loc_wipe (&loc;;
887953
-
887953
 next:
887953
                 cur_block++;
887953
-                if (!--call_count)
887953
-                        break;
887953
+                cur_block_idx++;
887953
         }
887953
-        if (local->unlink_shards_barriered)
887953
-                syncbarrier_wait (&local->barrier, count);
887953
+        syncbarrier_wait (&local->barrier, count);
887953
+        SHARD_UNSET_ROOT_FS_ID (frame, local);
887953
+        return 0;
887953
+}
887953
+
887953
+int
887953
+shard_regulated_shards_deletion (call_frame_t *cleanup_frame, xlator_t *this,
887953
+                                 int now, int first_block, gf_dirent_t *entry)
887953
+{
887953
+        int            i     = 0;
887953
+        int            ret   = 0;
887953
+        shard_local_t *local = NULL;
887953
+        uuid_t         gfid  = {0,};
887953
+
887953
+        local = cleanup_frame->local;
887953
+
887953
+        local->inode_list = GF_CALLOC (now, sizeof (inode_t *),
887953
+                                       gf_shard_mt_inode_list);
887953
+        if (!local->inode_list)
887953
+                return -ENOMEM;
887953
+
887953
+        local->first_block = first_block;
887953
+        local->last_block = first_block + now - 1;
887953
+        local->num_blocks = now;
887953
+        gf_uuid_parse (entry->d_name, gfid);
887953
+        gf_uuid_copy (local->base_gfid, gfid);
887953
+        local->resolver_base_inode = inode_find (this->itable, gfid);
887953
+        local->call_count = 0;
887953
+        syncbarrier_init (&local->barrier);
887953
+
887953
+        shard_common_resolve_shards (cleanup_frame, this,
887953
+                                     shard_post_resolve_unlink_handler);
887953
+
887953
+        for (i = 0; i < local->num_blocks; i++) {
887953
+                if (local->inode_list[i])
887953
+                        inode_unref (local->inode_list[i]);
887953
+        }
887953
+        GF_FREE (local->inode_list);
887953
+        local->inode_list = NULL;
887953
+        if (local->op_ret)
887953
+                ret = -local->op_errno;
887953
+        syncbarrier_destroy (&local->barrier);
887953
+        inode_unref (local->resolver_base_inode);
887953
+        local->resolver_base_inode = NULL;
887953
+        STACK_RESET (cleanup_frame->root);
887953
+        return ret;
887953
+}
887953
+
887953
+
887953
+int
887953
+__shard_delete_shards_of_entry (call_frame_t *cleanup_frame, xlator_t *this,
887953
+                                gf_dirent_t *entry, inode_t *inode)
887953
+{
887953
+        int              ret           = 0;
887953
+        int              shard_count   = 0;
887953
+        int              first_block   = 0;
887953
+        int              now           = 0;
887953
+        uint64_t         size          = 0;
887953
+        uint64_t         block_size    = 0;
887953
+        uint64_t         size_array[4] = {0,};
887953
+        void            *bsize         = NULL;
887953
+        void            *size_attr     = NULL;
887953
+        dict_t          *xattr_rsp     = NULL;
887953
+        loc_t            loc           = {0,};
887953
+        shard_local_t   *local         = NULL;
887953
+        shard_priv_t    *priv          = NULL;
887953
 
887953
+        priv = this->private;
887953
+        local = cleanup_frame->local;
887953
+        ret = dict_reset (local->xattr_req);
887953
+        if (ret) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
887953
+                        "Failed to reset dict");
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+
887953
+        ret = dict_set_uint64 (local->xattr_req, GF_XATTR_SHARD_BLOCK_SIZE, 0);
887953
+        if (ret) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
887953
+                        "Failed to set dict value: key:%s",
887953
+                        GF_XATTR_SHARD_BLOCK_SIZE);
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+
887953
+        ret = dict_set_uint64 (local->xattr_req, GF_XATTR_SHARD_FILE_SIZE,
887953
+                               8 * 4);
887953
+        if (ret) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
887953
+                        "Failed to set dict value: key:%s",
887953
+                        GF_XATTR_SHARD_FILE_SIZE);
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+
887953
+        loc.inode = inode_ref (inode);
887953
+        loc.parent = inode_ref (priv->dot_shard_rm_inode);
887953
+        ret = inode_path (loc.parent, entry->d_name, (char **)&(loc.path));
887953
+        if (ret < 0) {
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_INODE_PATH_FAILED,
887953
+                        "Inode path  failed on %s", entry->d_name);
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+
887953
+        loc.name = strrchr (loc.path, '/');
887953
+        if (loc.name)
887953
+                loc.name++;
887953
+        ret = syncop_lookup (FIRST_CHILD(this), &loc, NULL, NULL,
887953
+                             local->xattr_req, &xattr_rsp);
887953
+        if (ret)
887953
+                goto err;
887953
+
887953
+        ret = dict_get_ptr (xattr_rsp, GF_XATTR_SHARD_BLOCK_SIZE, &bsize);
887953
+        if (ret) {
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_OP_FAILED,
887953
+                        "Failed to get dict value: key:%s",
887953
+                        GF_XATTR_SHARD_BLOCK_SIZE);
887953
+                goto err;
887953
+        }
887953
+        block_size = ntoh64 (*((uint64_t *)bsize));
887953
+
887953
+        ret = dict_get_ptr (xattr_rsp, GF_XATTR_SHARD_FILE_SIZE, &size_attr);
887953
+        if (ret) {
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_OP_FAILED,
887953
+                        "Failed to get dict value: key:%s",
887953
+                        GF_XATTR_SHARD_FILE_SIZE);
887953
+                goto err;
887953
+        }
887953
+
887953
+        memcpy (size_array, size_attr, sizeof (size_array));
887953
+        size = ntoh64 (size_array[0]);
887953
+
887953
+        shard_count = (size / block_size) - 1;
887953
+        if (shard_count < 0) {
887953
+                gf_msg_debug (this->name, 0, "Size of %s hasn't grown beyond "
887953
+                              "its shard-block-size. Nothing to delete. "
887953
+                              "Returning", entry->d_name);
887953
+                /* File size < shard-block-size, so nothing to delete */
887953
+                ret = 0;
887953
+                goto delete_marker;
887953
+        }
887953
+        if ((size % block_size) > 0)
887953
+                shard_count++;
887953
+
887953
+        if (shard_count == 0) {
887953
+                gf_msg_debug (this->name, 0, "Size of %s is exactly equal to "
887953
+                              "its shard-block-size. Nothing to delete. "
887953
+                              "Returning", entry->d_name);
887953
+                ret = 0;
887953
+                goto delete_marker;
887953
+        }
887953
+        gf_msg_debug (this->name, 0, "base file = %s, "
887953
+                      "shard-block-size=%"PRIu64", file-size=%"PRIu64", "
887953
+                      "shard_count=%d", entry->d_name, block_size, size,
887953
+                      shard_count);
887953
+
887953
+        /* Perform a gfid-based lookup to see if gfid corresponding to marker
887953
+         * file's base name exists.
887953
+         */
887953
+        loc_wipe (&loc;;
887953
+        loc.inode = inode_new (this->itable);
887953
+        if (!loc.inode) {
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+        gf_uuid_parse (entry->d_name, loc.gfid);
887953
+        ret = syncop_lookup (FIRST_CHILD(this), &loc, NULL, NULL, NULL, NULL);
887953
+        if (!ret) {
887953
+                gf_msg_debug (this->name, 0, "Base shard corresponding to gfid "
887953
+                              "%s is present. Skipping shard deletion. "
887953
+                              "Returning", entry->d_name);
887953
+                ret = 0;
887953
+                goto delete_marker;
887953
+        }
887953
+
887953
+        first_block = 1;
887953
+
887953
+        while (shard_count) {
887953
+                if (shard_count < local->deletion_rate) {
887953
+                        now = shard_count;
887953
+                        shard_count = 0;
887953
+                } else {
887953
+                        now = local->deletion_rate;
887953
+                        shard_count -= local->deletion_rate;
887953
+                }
887953
+
887953
+                gf_msg_debug (this->name, 0, "deleting %d shards starting from "
887953
+                              "block %d of gfid %s", now, first_block,
887953
+                              entry->d_name);
887953
+                ret = shard_regulated_shards_deletion (cleanup_frame, this,
887953
+                                                       now, first_block,
887953
+                                                       entry);
887953
+                if (ret)
887953
+                        goto err;
887953
+                first_block += now;
887953
+        }
887953
+
887953
+delete_marker:
887953
+        loc_wipe (&loc;;
887953
+        loc.inode = inode_ref (inode);
887953
+        loc.parent = inode_ref (priv->dot_shard_rm_inode);
887953
+        ret = inode_path (loc.parent, entry->d_name, (char **)&(loc.path));
887953
+        if (ret < 0) {
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_INODE_PATH_FAILED,
887953
+                        "Inode path  failed on %s", entry->d_name);
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+        loc.name = strrchr (loc.path, '/');
887953
+        if (loc.name)
887953
+                loc.name++;
887953
+        ret = syncop_unlink (FIRST_CHILD(this), &loc, NULL, NULL);
887953
+        if (ret)
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0,
887953
+                        SHARD_MSG_SHARDS_DELETION_FAILED, "Failed to delete %s "
887953
+                        "from /%s", entry->d_name, GF_SHARD_REMOVE_ME_DIR);
887953
+err:
887953
+        if (xattr_rsp)
887953
+                dict_unref (xattr_rsp);
887953
+        loc_wipe (&loc;;
887953
+        return ret;
887953
+}
887953
+
887953
+int
887953
+shard_delete_shards_of_entry (call_frame_t *cleanup_frame, xlator_t *this,
887953
+                              gf_dirent_t *entry, inode_t *inode)
887953
+{
887953
+        int           ret  = -1;
887953
+        loc_t         loc  = {0,};
887953
+        shard_priv_t *priv = NULL;
887953
+
887953
+        priv = this->private;
887953
+        loc.inode = inode_ref (priv->dot_shard_rm_inode);
887953
+
887953
+        ret = syncop_entrylk (FIRST_CHILD(this), this->name, &loc,
887953
+                              entry->d_name, ENTRYLK_LOCK, ENTRYLK_WRLCK, NULL,
887953
+                              NULL);
887953
+        if (ret)
887953
+                goto out;
887953
+        {
887953
+                ret = __shard_delete_shards_of_entry (cleanup_frame, this,
887953
+                                                      entry, inode);
887953
+        }
887953
+        syncop_entrylk (FIRST_CHILD(this), this->name, &loc, entry->d_name,
887953
+                        ENTRYLK_UNLOCK, ENTRYLK_WRLCK, NULL, NULL);
887953
+out:
887953
+        loc_wipe (&loc;;
887953
+        return ret;
887953
+}
887953
+
887953
+int
887953
+shard_delete_shards_cbk (int ret, call_frame_t *frame, void *data)
887953
+{
887953
+        xlator_t     *this          = NULL;
887953
+        shard_priv_t *priv          = NULL;
887953
+
887953
+        this = frame->this;
887953
+        priv = this->private;
887953
+
887953
+        if (ret < 0) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, -ret,
887953
+                        SHARD_MSG_SHARDS_DELETION_FAILED,
887953
+                        "Background deletion of shards failed");
887953
+                priv->first_lookup = SHARD_FIRST_LOOKUP_PENDING;
887953
+        } else {
887953
+                priv->first_lookup = SHARD_FIRST_LOOKUP_DONE;
887953
+        }
887953
+        SHARD_STACK_DESTROY (frame);
887953
         return 0;
887953
 }
887953
 
887953
 int
887953
+shard_resolve_internal_dir (xlator_t *this, shard_local_t *local,
887953
+                            shard_internal_dir_type_t type)
887953
+{
887953
+        int                  ret   = 0;
887953
+        char                *bname = NULL;
887953
+        loc_t               *loc   = NULL;
887953
+        shard_priv_t        *priv  = NULL;
887953
+        uuid_t               gfid  = {0,};
887953
+        struct iatt          stbuf = {0,};
887953
+
887953
+        priv = this->private;
887953
+
887953
+        switch (type) {
887953
+        case SHARD_INTERNAL_DIR_DOT_SHARD:
887953
+                loc = &local->dot_shard_loc;
887953
+                gf_uuid_copy (gfid, priv->dot_shard_gfid);
887953
+                bname = GF_SHARD_DIR;
887953
+                break;
887953
+        case SHARD_INTERNAL_DIR_DOT_SHARD_REMOVE_ME:
887953
+                loc = &local->dot_shard_rm_loc;
887953
+                gf_uuid_copy (gfid, priv->dot_shard_rm_gfid);
887953
+                bname = GF_SHARD_REMOVE_ME_DIR;
887953
+                break;
887953
+        default:
887953
+                break;
887953
+        }
887953
+
887953
+        loc->inode = inode_find (this->itable, gfid);
887953
+        if (!loc->inode) {
887953
+                ret = shard_init_internal_dir_loc (this, local, type);
887953
+                if (ret)
887953
+                        goto err;
887953
+                ret = dict_reset (local->xattr_req);
887953
+                if (ret) {
887953
+                        gf_msg (this->name, GF_LOG_WARNING, 0,
887953
+                                SHARD_MSG_DICT_OP_FAILED, "Failed to reset "
887953
+                                "dict");
887953
+                        ret = -ENOMEM;
887953
+                        goto err;
887953
+                }
887953
+                ret = dict_set_static_bin (local->xattr_req, "gfid-req", gfid,
887953
+                                           16);
887953
+                ret = syncop_lookup (FIRST_CHILD(this), loc, &stbuf, NULL,
887953
+                                     local->xattr_req, NULL);
887953
+                if (ret < 0) {
887953
+                        if (ret != -ENOENT)
887953
+                                gf_msg (this->name, GF_LOG_ERROR, -ret,
887953
+                                        SHARD_MSG_SHARDS_DELETION_FAILED,
887953
+                                        "Lookup on %s failed, exiting", bname);
887953
+                        goto err;
887953
+                } else {
887953
+                        shard_link_internal_dir_inode (local,
887953
+                                                       loc->inode, &stbuf,
887953
+                                                       type);
887953
+                }
887953
+        }
887953
+        ret = 0;
887953
+err:
887953
+        return ret;
887953
+}
887953
+
887953
+int
887953
+shard_lookup_marker_entry (xlator_t *this, shard_local_t *local,
887953
+                           gf_dirent_t *entry)
887953
+{
887953
+        int   ret = 0;
887953
+        loc_t loc = {0,};
887953
+
887953
+        loc.inode = inode_new (this->itable);
887953
+        if (!loc.inode) {
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+        loc.parent = inode_ref (local->fd->inode);
887953
+
887953
+        ret = inode_path (loc.parent, entry->d_name, (char **)&(loc.path));
887953
+        if (ret < 0) {
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_INODE_PATH_FAILED,
887953
+                        "Inode path failed on %s", entry->d_name);
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+
887953
+        loc.name = strrchr (loc.path, '/');
887953
+        if (loc.name)
887953
+                loc.name++;
887953
+
887953
+        ret = syncop_lookup (FIRST_CHILD(this), &loc, NULL, NULL, NULL, NULL);
887953
+        if (ret < 0) {
887953
+                goto err;
887953
+        }
887953
+        entry->inode = inode_ref (loc.inode);
887953
+        ret = 0;
887953
+err:
887953
+        loc_wipe (&loc;;
887953
+        return ret;
887953
+}
887953
+
887953
+int
887953
+shard_delete_shards (void *opaque)
887953
+{
887953
+        int              ret                        = 0;
887953
+        off_t            offset                     = 0;
887953
+        loc_t            loc                        = {0,};
887953
+        inode_t         *link_inode                 = NULL;
887953
+        xlator_t        *this                       = NULL;
887953
+        shard_priv_t    *priv                       = NULL;
887953
+        shard_local_t   *local                      = NULL;
887953
+        gf_dirent_t      entries;
887953
+        gf_dirent_t     *entry                      = NULL;
887953
+        call_frame_t    *cleanup_frame              = NULL;
887953
+
887953
+        this = THIS;
887953
+        priv = this->private;
887953
+        INIT_LIST_HEAD (&entries.list);
887953
+
887953
+        cleanup_frame = opaque;
887953
+
887953
+        local = mem_get0 (this->local_pool);
887953
+        if (!local) {
887953
+                gf_msg (this->name, GF_LOG_WARNING, ENOMEM,
887953
+                        SHARD_MSG_MEMALLOC_FAILED, "Failed to create local to "
887953
+                        "delete shards");
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+        cleanup_frame->local = local;
887953
+
887953
+        local->xattr_req = dict_new ();
887953
+        if (!local->xattr_req) {
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+        local->deletion_rate = priv->deletion_rate;
887953
+
887953
+        ret = shard_resolve_internal_dir (this, local,
887953
+                                          SHARD_INTERNAL_DIR_DOT_SHARD);
887953
+        if (ret == -ENOENT) {
887953
+                gf_msg_debug (this->name, 0, ".shard absent. Nothing to"
887953
+                              " delete. Exiting");
887953
+                ret = 0;
887953
+                goto err;
887953
+        } else if (ret < 0) {
887953
+                goto err;
887953
+        }
887953
+
887953
+        ret = shard_resolve_internal_dir (this, local,
887953
+                                          SHARD_INTERNAL_DIR_DOT_SHARD_REMOVE_ME);
887953
+        if (ret == -ENOENT) {
887953
+                gf_msg_debug (this->name, 0, ".remove_me absent. "
887953
+                              "Nothing to delete. Exiting");
887953
+                ret = 0;
887953
+                goto err;
887953
+        } else if (ret < 0) {
887953
+                goto err;
887953
+        }
887953
+
887953
+        local->fd = fd_anonymous (local->dot_shard_rm_loc.inode);
887953
+        if (!local->fd) {
887953
+                ret = -ENOMEM;
887953
+                goto err;
887953
+        }
887953
+
887953
+        while ((ret = syncop_readdirp (FIRST_CHILD(this), local->fd, 131072,
887953
+                                      offset, &entries, local->xattr_req,
887953
+                                      NULL))) {
887953
+                if (ret > 0)
887953
+                        ret = 0;
887953
+                list_for_each_entry (entry, &entries.list, list) {
887953
+                        offset = entry->d_off;
887953
+
887953
+                        if (!strcmp (entry->d_name, ".") ||
887953
+                            !strcmp (entry->d_name, ".."))
887953
+                                continue;
887953
+
887953
+                        if (!entry->inode) {
887953
+                                ret = shard_lookup_marker_entry (this, local,
887953
+                                                                 entry);
887953
+                                if (ret < 0)
887953
+                                        continue;
887953
+                        }
887953
+                        link_inode = inode_link (entry->inode, local->fd->inode,
887953
+                                                 entry->d_name, &entry->d_stat);
887953
+
887953
+                        gf_msg_debug (this->name, 0, "Initiating deletion of "
887953
+                                      "shards of gfid %s", entry->d_name);
887953
+                        ret = shard_delete_shards_of_entry (cleanup_frame, this,
887953
+                                                            entry, link_inode);
887953
+                        inode_unlink (link_inode, local->fd->inode,
887953
+                                      entry->d_name);
887953
+                        inode_unref (link_inode);
887953
+                        if (ret) {
887953
+                                gf_msg (this->name, GF_LOG_ERROR, -ret,
887953
+                                        SHARD_MSG_SHARDS_DELETION_FAILED,
887953
+                                        "Failed to clean up shards of gfid %s",
887953
+                                        entry->d_name);
887953
+                                continue;
887953
+                        }
887953
+                        gf_msg (this->name, GF_LOG_INFO, 0,
887953
+                                SHARD_MSG_SHARDS_DELETION_COMPLETED, "Deleted "
887953
+                                "shards of gfid=%s from backend",
887953
+                                entry->d_name);
887953
+                }
887953
+                gf_dirent_free (&entries);
887953
+                if (ret)
887953
+                        break;
887953
+        }
887953
+        ret = 0;
887953
+err:
887953
+        loc_wipe (&loc;;
887953
+        return ret;
887953
+}
887953
+
887953
+int
887953
 shard_unlock_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                           int32_t op_ret, int32_t op_errno, dict_t *xdata)
887953
 {
887953
@@ -3394,7 +3900,10 @@ shard_unlink_base_file_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                 local->postoldparent = *postparent;
887953
                 if (xdata)
887953
                         local->xattr_rsp = dict_ref (xdata);
887953
+                if (local->cleanup_required)
887953
+                        shard_start_background_deletion (this);
887953
         }
887953
+
887953
         if (local->entrylk_frame) {
887953
                 ret = shard_unlock_entrylk (frame, this);
887953
                 if (ret < 0) {
887953
@@ -3408,6 +3917,7 @@ shard_unlink_base_file_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                 local->op_ret = -1;
887953
                 local->op_errno = -ret;
887953
         }
887953
+
887953
         shard_unlink_cbk (frame, this);
887953
         return 0;
887953
 }
887953
@@ -3576,6 +4086,7 @@ shard_post_lookup_base_shard_rm_handler (call_frame_t *frame, xlator_t *this)
887953
         } else {
887953
                 gf_msg_debug (this->name, 0, "link count on %s = 1, creating "
887953
                               "file under .remove_me", local->int_inodelk.loc.path);
887953
+                local->cleanup_required = _gf_true;
887953
                 shard_acquire_entrylk (frame, this, priv->dot_shard_rm_inode,
887953
                                        local->prebuf.ia_gfid);
887953
         }
887953
@@ -3788,20 +4299,6 @@ err:
887953
 }
887953
 
887953
 int
887953
-shard_rename_cbk (call_frame_t *frame, xlator_t *this)
887953
-{
887953
-        shard_local_t *local = NULL;
887953
-
887953
-        local = frame->local;
887953
-
887953
-        SHARD_STACK_UNWIND (rename, frame, local->op_ret, local->op_errno,
887953
-                            &local->prebuf, &local->preoldparent,
887953
-                            &local->postoldparent, &local->prenewparent,
887953
-                            &local->postnewparent, local->xattr_rsp);
887953
-        return 0;
887953
-}
887953
-
887953
-int
887953
 shard_post_rename_lookup_handler (call_frame_t *frame, xlator_t *this)
887953
 {
887953
         shard_rename_cbk (frame, this);
887953
@@ -3854,6 +4351,8 @@ shard_rename_src_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                         local->op_errno = -ret;
887953
                         goto err;
887953
                 }
887953
+                if (local->cleanup_required)
887953
+                        shard_start_background_deletion (this);
887953
         }
887953
 
887953
         /* Now the base file of src, if sharded, is looked up to gather ia_size
887953
@@ -4822,7 +5321,7 @@ shard_common_inode_write_do (call_frame_t *frame, xlator_t *this)
887953
 
887953
         if (dict_set_uint32 (local->xattr_req,
887953
                              GLUSTERFS_WRITE_UPDATE_ATOMIC, 4)) {
887953
-                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_SET_FAILED,
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_OP_FAILED,
887953
                         "Failed to set "GLUSTERFS_WRITE_UPDATE_ATOMIC" into "
887953
                         "dict: %s", uuid_utoa (fd->inode->gfid));
887953
                 local->op_ret = -1;
887953
@@ -5141,7 +5640,7 @@ shard_mkdir_internal_dir (call_frame_t *frame, xlator_t *this,
887953
 
887953
         ret = dict_set_bin (xattr_req, "gfid-req", *gfid, 16);
887953
         if (ret) {
887953
-                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_SET_FAILED,
887953
+                gf_msg (this->name, GF_LOG_ERROR, 0, SHARD_MSG_DICT_OP_FAILED,
887953
                         "Failed to set gfid-req for %s",
887953
                         shard_internal_dir_string (type));
887953
                 goto err;
887953
@@ -6186,6 +6685,8 @@ init (xlator_t *this)
887953
 
887953
         GF_OPTION_INIT ("shard-block-size", priv->block_size, size_uint64, out);
887953
 
887953
+        GF_OPTION_INIT ("shard-deletion-rate", priv->deletion_rate, uint32, out);
887953
+
887953
         this->local_pool = mem_pool_new (shard_local_t, 128);
887953
         if (!this->local_pool) {
887953
                 ret = -1;
887953
@@ -6241,6 +6742,8 @@ reconfigure (xlator_t *this, dict_t *options)
887953
         GF_OPTION_RECONF ("shard-block-size", priv->block_size, options, size,
887953
                           out);
887953
 
887953
+        GF_OPTION_RECONF ("shard-deletion-rate", priv->deletion_rate, options,
887953
+                          uint32, out);
887953
         ret = 0;
887953
 
887953
 out:
887953
@@ -6364,5 +6867,12 @@ struct volume_options options[] = {
887953
            .description = "The size unit used to break a file into multiple "
887953
                           "chunks",
887953
         },
887953
+        {  .key = {"shard-deletion-rate"},
887953
+           .type = GF_OPTION_TYPE_INT,
887953
+           .default_value = "100",
887953
+           .min = 100,
887953
+           .max = INT_MAX,
887953
+           .description = "The number of shards to send deletes on at a time",
887953
+        },
887953
         { .key = {NULL} },
887953
 };
887953
diff --git a/xlators/features/shard/src/shard.h b/xlators/features/shard/src/shard.h
887953
index 1783ff6..5de098a 100644
887953
--- a/xlators/features/shard/src/shard.h
887953
+++ b/xlators/features/shard/src/shard.h
887953
@@ -130,9 +130,9 @@ shard_unlock_entrylk (call_frame_t *frame, xlator_t *this);
887953
                               sizeof (*__bs));                                \
887953
         if (__ret) {                                                          \
887953
                 gf_msg (this->name, GF_LOG_WARNING, 0,                        \
887953
-                        SHARD_MSG_DICT_SET_FAILED, "Failed to set key: %s "   \
887953
+                        SHARD_MSG_DICT_OP_FAILED, "Failed to set key: %s "    \
887953
                         "on path %s", GF_XATTR_SHARD_BLOCK_SIZE, (loc)->path);\
887953
-                GF_FREE (__bs);                                               \
887953
+                        GF_FREE (__bs);                                       \
887953
                 goto label;                                                   \
887953
         }                                                                     \
887953
                                                                               \
887953
@@ -144,7 +144,7 @@ shard_unlock_entrylk (call_frame_t *frame, xlator_t *this);
887953
                               __size_attr, 8 * 4);                            \
887953
         if (__ret) {                                                          \
887953
                 gf_msg (this->name, GF_LOG_WARNING, 0,                        \
887953
-                        SHARD_MSG_DICT_SET_FAILED, "Failed to set key: %s "   \
887953
+                        SHARD_MSG_DICT_OP_FAILED, "Failed to set key: %s "   \
887953
                         "on path %s", GF_XATTR_SHARD_FILE_SIZE, (loc)->path);   \
887953
                 GF_FREE (__size_attr);                                        \
887953
                 goto label;                                                   \
887953
@@ -160,7 +160,7 @@ shard_unlock_entrylk (call_frame_t *frame, xlator_t *this);
887953
                 local->op_ret = -1;                                           \
887953
                 local->op_errno = ENOMEM;                                     \
887953
                 gf_msg (this->name, GF_LOG_WARNING, 0,                        \
887953
-                        SHARD_MSG_DICT_SET_FAILED, "Failed to set dict value:"\
887953
+                        SHARD_MSG_DICT_OP_FAILED, "Failed to set dict value:"\
887953
                         " key:%s for %s.", GF_XATTR_SHARD_FILE_SIZE,          \
887953
                         uuid_utoa (gfid));                                    \
887953
                 goto label;                                                   \
887953
@@ -197,6 +197,12 @@ shard_unlock_entrylk (call_frame_t *frame, xlator_t *this);
887953
                 }                                                             \
887953
         } while (0)
887953
 
887953
+typedef enum {
887953
+        SHARD_FIRST_LOOKUP_PENDING = 0,
887953
+        SHARD_FIRST_LOOKUP_IN_PROGRESS,
887953
+        SHARD_FIRST_LOOKUP_DONE,
887953
+} shard_first_lookup_state_t;
887953
+
887953
 /* rm = "remove me" */
887953
 
887953
 typedef struct shard_priv {
887953
@@ -208,6 +214,8 @@ typedef struct shard_priv {
887953
         gf_lock_t lock;
887953
         int inode_count;
887953
         struct list_head ilist_head;
887953
+        uint32_t deletion_rate;
887953
+        shard_first_lookup_state_t first_lookup;
887953
 } shard_priv_t;
887953
 
887953
 typedef struct {
887953
@@ -303,6 +311,9 @@ typedef struct shard_local {
887953
         call_frame_t *main_frame;
887953
         call_frame_t *inodelk_frame;
887953
         call_frame_t *entrylk_frame;
887953
+        uint32_t deletion_rate;
887953
+        gf_boolean_t cleanup_required;
887953
+        uuid_t base_gfid;
887953
 } shard_local_t;
887953
 
887953
 typedef struct shard_inode_ctx {
887953
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
887953
index 5a697cf..4357562 100644
887953
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
887953
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
887953
@@ -3298,6 +3298,11 @@ struct volopt_map_entry glusterd_volopt_map[] = {
887953
           .op_version = GD_OP_VERSION_3_7_0,
887953
           .flags      = OPT_FLAG_CLIENT_OPT
887953
         },
887953
+        { .key        = "features.shard-deletion-rate",
887953
+          .voltype    = "features/shard",
887953
+          .op_version = GD_OP_VERSION_4_2_0,
887953
+          .flags      = OPT_FLAG_CLIENT_OPT
887953
+        },
887953
         { .key        = "features.scrub-throttle",
887953
           .voltype    = "features/bit-rot",
887953
           .value      = "lazy",
887953
-- 
887953
1.8.3.1
887953