2.66 regression: Unable to copy files on a ZFS volume configured with noatime
Steps to reproduce
- Have the ZFS-on-Linux out-of-tree kernel module (Debian: install
zfs-dkms
and reboot) sudo truncate --size=1G /zfs1
sudo zpool create pool1 /zfs1
sudo zfs create pool1/mnt
cd /pool1/mnt
sudo touch x
sudo zfs set atime=off pool1
sudo gio copy x y
Steps that do not reproduce this issue
- Mounting an ext4 filesystem with
mount -o remount,noatime
and using that - Mounting a ZFS filesystem with
mount -o remount,noatime
and using that (only setting the flag on the pool seems to reproduce this)
Expected result
The empty file x is copied to y.
Actual result
gio: file:///pool1/mnt/x: Error when getting information for file descriptor: Numerical result out of range
Trying this under strace, it seems that the problem is that ZFS with noatime
clears the STATX_ATIME
bit in the mask, similar to #2189 (closed).
statx(AT_FDCWD, "/pool1/mnt/x",
AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
STATX_ALL,
{stx_mask=STATX_TYPE|STATX_MODE|STATX_NLINK|STATX_UID|STATX_GID|
STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|0x1000,
stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=0, ...}) = 0
openat(AT_FDCWD, "/pool1/mnt/x", O_RDONLY) = 7
statx(7, "",
AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH,
STATX_TYPE,
{stx_mask=STATX_TYPE|STATX_MODE|STATX_NLINK|STATX_UID|STATX_GID|
STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|0x1000,
stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=0, ...}) = 0
futex(0x7fdaef5c3f38, FUTEX_WAKE_PRIVATE, 2147483647) = 0
futex(0x7fdaef5c3f38, FUTEX_WAKE_PRIVATE, 2147483647) = 0
futex(0x7fdaef5c3f38, FUTEX_WAKE_PRIVATE, 2147483647) = 0
statx(7, "",
AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL,
{stx_mask=STATX_TYPE|STATX_MODE|STATX_NLINK|STATX_UID|STATX_GID|
STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|0x1000,
stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=0, ...}) = 0
(My strace
does not understand STATX_MNT_ID
, which is 0x1000.)
I think the short-term solution is: never include STATX_ATIME
in the required mask.
As a longer-term solution, it might be better to assume that nothing is guaranteed. <linux/statx.h>
says:
Items in STATX_BASIC_STATS may be marked unavailable on return, but they will have values installed for compatibility purposes so that stat() and co. can be emulated in userspace.
So it might be better to have a dual strategy:
- for general-purpose
stat()
-equivalents likeg_file_query_info()
, check thestx_mask
every time we copy information from thestruct statx
to theGFileInfo
; - for internal uses like
g_local_file_measure_size_of_file()
, don't check the flags and just assume that the compatibility values filled in by the kernel are sensible, because if they were not, it would have broken older code that callsstat()
and friends