One of the customer faced I/O errors while archiving a huge file 11 TB
and observed that after Tar had hit read I/O error due to xfs
filesystem, it still continue writing 0's to the file using strace.
However there was no indication for tar that it was writing 0's when
the error occurred.

Later it was found that it is expected behavior to write 0's as the
file header is already written. Hence, it need to be padded with 0's.

Using the reproducing steps provided by customer, we can see this behavior.

Padding 0's is expected behavior however it does so silently (for Read
error at byte...), it should say it is Padding with zeros similar to
how it reports "File Shrank , padding with zeroes"

During the reproducer steps provided by customer we see that sometimes
tar report "Read I/O errors" as "File shrank, padding with 0" , we see
in the step(2) provided.

Reproducer available here:

#!/bin/bash
# Reproducer "tardust"
#
# When "tar create" reads a file there are several shortcomings when
it hits read error
#
# 1) When read() returns 0 bytes due to read error, then this happens
# read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# read(4, 0x563adef7b000, 3584) = -1 EIO (Input/output error)
# write(2, "tar: ", 5tar: ) = 5
# write(2, "/mntx/testfile: Read error at by"..., 70/mntx/testfile:
Read error at byte 260653056, while reading 3584 bytes) = 70
# write(2, ": Input/output error", 20: Input/output error) = 20
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# Actual behaviour: it prints a message about "Read error", but it
conceals the information it will pad the output with zeros
# Expected behaviour: it should also print the information "padding with zero"
# 2) There is a 2nd shortcoming about tar not differentiate between
"read error" and "file shrinkage"
# That means when it sees a short read due to read error, it does not
report read error.
# It looks like this:
# read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 2560          <<< HERE
# write(2, "tar: ", 5tar: ) = 5
# write(2, "/mntx/testfile: File shrank by 5"..., 65/mntx/testfile:
File shrank by 53927936 bytes; padding with zeros) = 65
# write(2, "\n", 1
# ) = 1
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# Summary: A read error is not reported here. At least it now says
"padding with zeros"
# Expected behaviour: it should report a read error, so the user knows
what it going on.
#
# 3) Side-Note:
# The blocking factor is applied to the output. When reading a file,
all reads are misaligned by 512 bytes.
# This is because it writes a 512 header for every archived file.
# That means the first read from file is 512bytes too short:
# Running with tar-blocking-factor=7
# fstat(1, {st_mode=S_IFREG|0644, st_size=17827, ...}) = 0
# write(1, "/mntx/testfile\n", 15/mntx/testfile
# ) = 15
# read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3072) = 3072 #1st read 512bytes too short
# write(3, "mntx/testfile\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
# write(3, 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
3584) = 3584
#
# 4) Reproducer overview:
# - Create a 500MB testimage, then create a testfile1 in the image
# - Use losetup/dmsetup with the "dust" target type
# - you can inject IO errors at specified block number in "dust"
# - You must hit a 4K boundary to see EIO, so use tar-blocking-factor=7 and
# - vary the bad blocknumber to find the case (1)
echo Step 1 Create disk image
dd if=/dev/zero of=/tmp/testimage bs=1M count=500 || exit
echo Step 2 Create XFS in image
mkfs.xfs /tmp/testimage || exit
echo Step 3 Use losetup so the file can be used a block device
losetup /dev/loop1 /tmp/testimage || exit
losetup
echo Step 6 Now create the testfile, this will have read error injected later
mkdir /mntx
mount /dev/loop1 /mntx || exit
dd if=/dev/zero of=/mntx/testfile bs=1M count=300 || exit
umount /mntx
echo Step7 Now iterating through bad blocks
echo As result, there are strace output file a1000 ... a1040
for i in `seq 1000 1 1040`
do
echo
echo Badblock $i
let ERR=i
let ERR1=i+1
let NUMSECTOR2=1024000-ERR1
#echo ERR1 is $ERR1
#echo NUMSECTOR2 is $NUMSECTOR2
dmsetup create tardust <<EOF
0 $ERR linear /dev/loop1 0
$ERR 1 error
$ERR1 $NUMSECTOR2 linear /dev/loop1 $ERR1
EOF
#dmsetup ls
#dmsetup status
#dmsetup table
mount /dev/mapper/tardust /mntx || exit
strace tar cvbf 7 /tmp/tardust.tar /mntx/testfile >&/tmp/a$i
umount /mntx
dmsetup remove tardust
grep -e error -e shrank /tmp/a$i
done
echo "Done: inspect the strace output file for error behaviour (grep
error ; Look at last read()-call )"
losetup -d /dev/loop1

=================

Actual results:
- When tar hits a disk read error when reading file from disk and
creating an archive, then it prints "file shrank"
- then it writes zeros (aka padding) according to initial file size
(but does not print that message)
- This happens in most cases (due to tar-block-size / disk-block-size
/ read-shift-by-512-bytes interaction)
- I provided a reproducer which shows under which circumstances it
correctly prints "Read error at byte…"

Expected results:
- When there is a read error, THEN tar shall report a read error
- When there is a read error, THEN tar shall NOT report a "file shrank"
- In addition it SHALL print "Padding with zeros". This is missing currently.


Regards,

Ondrej Dubaj

Reply via email to