cluster/distribute: Preserve file size during rebalance migration

If holes are encountered, then we do not write these to the dst,
which sometimes causes file size to be lesser than src. Data is not
corrupted, as when non-zero reads are received, we do write that data.

Calling a truncrate to give file size to prevent it from being
truncated to less than src in case the file end has holes.

Thanks to Brian Foster for providing the test case

Change-Id: I3cdd143b63ec8d797273d76189dff8b05eb9e551
BUG: 915554
Signed-off-by: shishir gowda <sgowda@redhat.com>
Reviewed-on: http://review.gluster.org/4574
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Anand Avati <avati@redhat.com>
This commit is contained in:
shishir gowda 2013-02-25 10:02:15 +05:30 committed by Anand Avati
parent 3f1ef648b9
commit 164c9586ae
3 changed files with 94 additions and 0 deletions

75
tests/bugs/bug-915554.t Executable file
View File

@ -0,0 +1,75 @@
#!/bin/bash
#
# Bug <915554>
#
# This test checks for a condition where a rebalance migrates a file and does
# not preserve the original file size. This can occur due to hole preservation
# logic in the file migration code. If a file size is aligned to a disk sector
# boundary (512b) and the tail portion of the file is zero-filled, the file
# may end up truncated to the end of the last data region in the file.
#
###
. $(dirname $0)/../include.rc
. $(dirname $0)/../dht.rc
cleanup;
TEST glusterd
TEST pidof glusterd
BRICK_COUNT=3
# create, start and mount a two brick DHT volume
TEST $CLI volume create $V0 $H0:$B0/${V0}0 $H0:$B0/${V0}1 $H0:$B0/${V0}2
TEST $CLI volume start $V0
TEST glusterfs --attribute-timeout=0 --entry-timeout=0 --gid-timeout=-1 -s $H0 --volfile-id $V0 $M0;
i=1
# Write some data to a file and extend such that the file is sparse to a sector
# aligned boundary.
echo test > $M0/$i
TEST truncate --size=1m $M0/$i
# cache the original size
SIZE1=`stat -c %s $M0/$i`
# rename till file gets a linkfile
while [ $i -ne 0 ]
do
test=`mv $M0/$i $M0/$(( $i+1 )) 2>/dev/null`
if [ $? -ne 0 ]
then
echo "rename failed"
break
fi
let i++
file_has_linkfile $i
has_link=$?
if [ $has_link -eq 2 ]
then
break;
fi
done
# start a rebalance (force option to overide checks) to trigger migration of
# file
TEST $CLI volume rebalance $V0 start force
# check if rebalance has completed for upto 15 secs
EXPECT_WITHIN 15 "0" rebalance_completed
# validate the file size after the migration
SIZE2=`stat -c %s $M0/$i`
TEST [ $SIZE1 -eq $SIZE2 ]
TEST rm -f $M0/$i
TEST umount $M0
TEST $CLI volume stop $V0
TEST $CLI volume delete $V0
cleanup;

View File

@ -70,3 +70,16 @@ function get_hashed_brick()
return $hashed
}
function rebalance_completed()
{
val=1
test=`gluster volume rebalance $V0 status |grep localhost|grep -v "in progress" 2>&1`
if [ $? -eq 0 ]
then
val=0
fi
echo $val
}

View File

@ -300,6 +300,12 @@ __dht_rebalance_create_dst_file (xlator_t *to, xlator_t *from, loc_t *loc, struc
goto out;
}
ret = syncop_ftruncate (to, fd, stbuf->ia_size);
if (ret < 0)
gf_log (this->name, GF_LOG_ERROR,
"ftruncate failed for %s on %s (%s)",
loc->path, to->name, strerror (errno));
ret = syncop_fsetattr (to, fd, stbuf,
(GF_SET_ATTR_UID | GF_SET_ATTR_GID),
NULL, NULL);