+lseek_test_430() {
+ local offset
+ local file=$1
+
+ # data at [200K, 400K)
+ dd if=/dev/urandom of=$file bs=256K count=1 seek=1 ||
+ error "256K->512K dd fails"
+ # data at [2M, 3M)
+ dd if=/dev/urandom of=$file bs=1M count=1 seek=2 ||
+ error "2M->3M dd fails"
+ # data at [4M, 5M)
+ dd if=/dev/urandom of=$file bs=1M count=1 seek=4 ||
+ error "4M->5M dd fails"
+ echo "Data at 256K...512K, 2M...3M and 4M...5M"
+ # start at first component hole #1
+ printf "Seeking hole from 1000 ... "
+ offset=$(lseek_test -l 1000 $file)
+ echo $offset
+ [[ $offset == 1000 ]] || error "offset $offset != 1000"
+ printf "Seeking data from 1000 ... "
+ offset=$(lseek_test -d 1000 $file)
+ echo $offset
+ [[ $offset == 262144 ]] || error "offset $offset != 262144"
+
+ # start at first component data block
+ printf "Seeking hole from 300000 ... "
+ offset=$(lseek_test -l 300000 $file)
+ echo $offset
+ [[ $offset == 524288 ]] || error "offset $offset != 524288"
+ printf "Seeking data from 300000 ... "
+ offset=$(lseek_test -d 300000 $file)
+ echo $offset
+ [[ $offset == 300000 ]] || error "offset $offset != 300000"
+
+ # start at the first component but beyond end of object size
+ printf "Seeking hole from 1000000 ... "
+ offset=$(lseek_test -l 1000000 $file)
+ echo $offset
+ [[ $offset == 1000000 ]] || error "offset $offset != 1000000"
+ printf "Seeking data from 1000000 ... "
+ offset=$(lseek_test -d 1000000 $file)
+ echo $offset
+ [[ $offset == 2097152 ]] || error "offset $offset != 2097152"
+
+ # start at second component stripe 2 (empty file)
+ printf "Seeking hole from 1500000 ... "
+ offset=$(lseek_test -l 1500000 $file)
+ echo $offset
+ [[ $offset == 1500000 ]] || error "offset $offset != 1500000"
+ printf "Seeking data from 1500000 ... "
+ offset=$(lseek_test -d 1500000 $file)
+ echo $offset
+ [[ $offset == 2097152 ]] || error "offset $offset != 2097152"
+
+ # start at second component stripe 1 (all data)
+ printf "Seeking hole from 3000000 ... "
+ offset=$(lseek_test -l 3000000 $file)
+ echo $offset
+ [[ $offset == 3145728 ]] || error "offset $offset != 3145728"
+ printf "Seeking data from 3000000 ... "
+ offset=$(lseek_test -d 3000000 $file)
+ echo $offset
+ [[ $offset == 3000000 ]] || error "offset $offset != 3000000"
+
+ dd if=/dev/urandom of=$file bs=640K count=1 seek=1 ||
+ error "2nd dd fails"
+ echo "Add data block at 640K...1280K"
+
+ # start at before new data block, in hole
+ printf "Seeking hole from 600000 ... "
+ offset=$(lseek_test -l 600000 $file)
+ echo $offset
+ [[ $offset == 600000 ]] || error "offset $offset != 600000"
+ printf "Seeking data from 600000 ... "
+ offset=$(lseek_test -d 600000 $file)
+ echo $offset
+ [[ $offset == 655360 ]] || error "offset $offset != 655360"
+
+ # start at the first component new data block
+ printf "Seeking hole from 1000000 ... "
+ offset=$(lseek_test -l 1000000 $file)
+ echo $offset
+ [[ $offset == 1310720 ]] || error "offset $offset != 1310720"
+ printf "Seeking data from 1000000 ... "
+ offset=$(lseek_test -d 1000000 $file)
+ echo $offset
+ [[ $offset == 1000000 ]] || error "offset $offset != 1000000"
+
+ # start at second component stripe 2, new data
+ printf "Seeking hole from 1200000 ... "
+ offset=$(lseek_test -l 1200000 $file)
+ echo $offset
+ [[ $offset == 1310720 ]] || error "offset $offset != 1310720"
+ printf "Seeking data from 1200000 ... "
+ offset=$(lseek_test -d 1200000 $file)
+ echo $offset
+ [[ $offset == 1200000 ]] || error "offset $offset != 1200000"
+
+ # start beyond file end
+ printf "Using offset > filesize ... "
+ lseek_test -l 4000000 $file && error "lseek should fail"
+ printf "Using offset > filesize ... "
+ lseek_test -d 4000000 $file && error "lseek should fail"
+
+ printf "Done\n\n"
+}
+
+test_430a() {
+ $LCTL get_param mdc.*.import | grep -q 'connect_flags:.*seek' ||
+ skip "MDT does not support SEEK_HOLE"
+
+ $LCTL get_param osc.*.import | grep -q 'connect_flags:.*seek' ||
+ skip "OST does not support SEEK_HOLE"
+
+ local file=$DIR/$tdir/$tfile
+
+ mkdir -p $DIR/$tdir
+
+ $LFS setstripe -E 1M -L mdt -E eof -c2 $file
+ # OST stripe #1 will have continuous data at [1M, 3M)
+ # OST stripe #2 is empty
+ echo "Component #1: 1M DoM, component #2: EOF, 2 stripes 1M"
+ lseek_test_430 $file
+ rm $file
+ $LFS setstripe -E 1M -c2 -S 64K -E 10M -c2 -S 1M $file
+ echo "Component #1: 1M, 2 stripes 64K, component #2: EOF, 2 stripes 1M"
+ lseek_test_430 $file
+ rm $file
+ $LFS setstripe -c2 -S 512K $file
+ echo "Two stripes, stripe size 512K"
+ lseek_test_430 $file
+ rm $file
+ # FLR with stale mirror
+ $LFS setstripe -N -E 512K -c1 -S 64K -E eof -c2 -S 512K \
+ -N -c2 -S 1M $file
+ echo "Mirrored file:"
+ echo "Component #1: 512K, stripe 64K, component #2: EOF, 2 stripes 512K"
+ echo "Plain 2 stripes 1M"
+ lseek_test_430 $file
+ rm $file
+}
+run_test 430a "lseek: SEEK_DATA/SEEK_HOLE basic functionality"
+
+test_430b() {
+ $LCTL get_param osc.*.import | grep -q 'connect_flags:.*seek' ||
+ skip "OST does not support SEEK_HOLE"
+
+ local offset
+ local file=$DIR/$tdir/$tfile
+
+ mkdir -p $DIR/$tdir
+ # Empty layout lseek should fail
+ $MCREATE $file
+ # seek from 0
+ printf "Seeking hole from 0 ... "
+ lseek_test -l 0 $file && error "lseek should fail"
+ printf "Seeking data from 0 ... "
+ lseek_test -d 0 $file && error "lseek should fail"
+ rm $file
+
+ # 1M-hole file
+ $LFS setstripe -E 1M -c2 -E eof $file
+ $TRUNCATE $file 1048576
+ printf "Seeking hole from 1000000 ... "
+ offset=$(lseek_test -l 1000000 $file)
+ echo $offset
+ [[ $offset == 1000000 ]] || error "offset $offset != 1000000"
+ printf "Seeking data from 1000000 ... "
+ lseek_test -d 1000000 $file && error "lseek should fail"
+ rm $file
+
+ # full component followed by non-inited one
+ $LFS setstripe -E 1M -c2 -E eof $file
+ dd if=/dev/urandom of=$file bs=1M count=1
+ printf "Seeking hole from 1000000 ... "
+ offset=$(lseek_test -l 1000000 $file)
+ echo $offset
+ [[ $offset == 1048576 ]] || error "offset $offset != 1048576"
+ printf "Seeking hole from 1048576 ... "
+ lseek_test -l 1048576 $file && error "lseek should fail"
+ # init second component and truncate back
+ echo "123" >> $file
+ $TRUNCATE $file 1048576
+ printf "Seeking hole from 1000000 ... "
+ offset=$(lseek_test -l 1000000 $file)
+ echo $offset
+ [[ $offset == 1048576 ]] || error "offset $offset != 1048576"
+ printf "Seeking hole from 1048576 ... "
+ lseek_test -l 1048576 $file && error "lseek should fail"
+ # boundary checks for big values
+ dd if=/dev/urandom of=$file.10g bs=1 count=1 seek=10G
+ offset=$(lseek_test -d 0 $file.10g)
+ [[ $offset == 10737418240 ]] || error "offset $offset != 10737418240"
+ dd if=/dev/urandom of=$file.100g bs=1 count=1 seek=100G
+ offset=$(lseek_test -d 0 $file.100g)
+ [[ $offset == 107374182400 ]] || error "offset $offset != 107374182400"
+ return 0
+}
+run_test 430b "lseek: SEEK_DATA/SEEK_HOLE special cases"
+
+test_430c() {
+ $LCTL get_param osc.*.import | grep -q 'connect_flags:.*seek' ||
+ skip "OST does not support SEEK_HOLE"
+
+ local file=$DIR/$tdir/$tfile
+ local start
+
+ mkdir -p $DIR/$tdir
+ dd if=/dev/urandom of=$file bs=1k count=1 seek=5M
+
+ # cp version 8.33+ prefers lseek over fiemap
+ if [[ $(cp --version | head -n1 | sed "s/[^0-9]//g") -ge 833 ]]; then
+ start=$SECONDS
+ time cp $file /dev/null
+ (( SECONDS - start < 5 )) ||
+ error "cp: too long runtime $((SECONDS - start))"
+
+ fi
+ # tar version 1.29+ supports SEEK_HOLE/DATA
+ if [[ $(tar --version | head -n1 | sed "s/[^0-9]//g") -ge 129 ]]; then
+ start=$SECONDS
+ time tar cS $file - | cat > /dev/null
+ (( SECONDS - start < 5 )) ||
+ error "tar: too long runtime $((SECONDS - start))"
+ fi
+}
+run_test 430c "lseek: external tools check"
+
+test_431() { # LU-14187
+ local file=$DIR/$tdir/$tfile
+
+ mkdir -p $DIR/$tdir
+ $LFS setstripe -c 1 -i 0 $file || error "lfs setstripe failed"
+ dd if=/dev/urandom of=$file bs=4k count=1
+ dd if=/dev/urandom of=$file bs=4k count=1 seek=10 conv=notrunc
+ dd if=/dev/urandom of=$file bs=4k count=1 seek=12 conv=notrunc
+ #define OBD_FAIL_OST_RESTART_IO 0x251
+ do_facet ost1 "$LCTL set_param fail_loc=0x251"
+ $LFS setstripe -c 1 -i 0 $file.0 || error "lfs setstripe failed"
+ cp $file $file.0
+ cancel_lru_locks
+ sync_all_data
+ echo 3 > /proc/sys/vm/drop_caches
+ diff $file $file.0 || error "data diff"
+}
+run_test 431 "Restart transaction for IO"
+