btrfs: log a message when dropping an extent due to IO error
When an IO error occurs while writing a datacow file, btrfs will drop the
extent containing the unwritten blocks. This prevents potential leaks
of information stored in the unwritten data blocks back to userspace, but
it is also a data loss event that is not easily visible from userspace.
The existing code does notify userspace of the error via the inode,
and the notification can be received through fsync (for the inode) or
syncfs (for any dirty inode on the filesystem) return values; however,
for the common case of a process that writes to a file and exits with
its data still in dirty cache pages, there is no process left to notify
when the ordered writes eventually fail.
In most cases the extent drop is preceded by error messages from the
write operation, but the IOERR bit can be set for less visible or obvious
reasons, like running out of memory, bad metadata, or as a result of
bugs that appear in other parts of btrfs from time to time.
Some of the existing error messages for writes contain only logical
addresses, while other messages contain only disk bytenrs. For read
errors, only one address is necessary, as the user can look up the other
with `btrfs ins log -o` or `btrfs ins sub/ino`, but for write errors, the
mapping between these addresses is removed when the error is detected in
btrfs_finish_one_ordered, so we can't derive one address from the other.
We need both addresses for separate purposes: the logical address to
identify which files have missing data, and the disk bytenr to identify
which part of the filesystem address space is failing to accept writes
(resolvable to device sectors through the chunk tree).
For now, inform the sysadmin that the data has been dropped by logging a
message when it happens, including both the logical subvol/inode/offset
triple and the disk bytenr, and the corresponding sizes.
In the future we might want to add some stats counters for this event,
similar to the dev stats counters, but not tied to any specific device.
The first step is to detect and report the events at all.
Other notes:
Because the extent is dropped, the lost data cannot be detected by a csum
mismatch or read failure, i.e. everything will look OK if the file is read
or the filesystem scrubbed, but an application will notice a truncated
file or a file with data replaced by zeros. For datasum files, we could
simply keep the extent as-is, allow future reads or csum verification
to fail, and report EIO errors that way. That is a larger and riskier
change to btrfs behavior than simply adding some passive monitoring of
the status quo. This approach also has problems with csum collisions,
it doesn't work for nodatasum+datacow files, and it takes much longer
for the errors to be detected and reported to a sysadmin.
nodatacow files don't have their extents dropped; instead, they will
simply have garbage in the blocks where the writes failed. In most
use cases for nodatacow files (e.g. VM disk images or databases), the
user will be running all writes through fsync(), O_DIRECT, or similar
mechanisms that can observe the existing EIO return value notification
path, so there's less need for diagnostic coverage in the kernel log
for nodatacow files.