3

I have an NFS mount served from a Linux server to a FreeBSD client. If I use touch to set the atime and mtime of a file on the FreeBSD client,

tavianator@muon $ touch -at "199112140000" ./foo
tavianator@muon $ touch -mt "199112150000" ./foo

then print the stat times,

tavianator@muon $ stat -f $'Access: %Sa\nModify: %Sm\nChange: %Sc\n Birth: %SB' ./foo
Access: Dec 14 00:00:00 1991
Modify: Jun 22 16:44:08 2023
Change: Dec 15 00:00:00 1991
 Birth: Jun 22 16:45:56 2023

the ctime and mtime are switched! However, the view from the Linux server is correct:

tavianator@tachyon $ stat /srv/nfs/freebsd/usr/home/tavianator/foo
  File: /srv/nfs/freebsd/usr/home/tavianator/foo
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 0,33    Inode: 54691999    Links: 1
Access: (0640/-rw-r-----)  Uid: ( 1000/tavianator)   Gid: ( 1000/tavianator)
Access: 1991-12-14 00:00:00.000000000 -0500
Modify: 1991-12-15 00:00:00.000000000 -0500
Change: 2023-06-22 16:45:56.731038486 -0400
 Birth: 2023-06-22 16:44:08.075496568 -0400

Any idea what could cause this, or how to fix it? Some more information that might be helpful:

root@tachyon ~ # uname -a
Linux tachyon 6.3.8-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 14 Jun 2023 20:10:31 +0000 x86_64 GNU/Linux
root@tachyon ~ # findmnt -T /srv/nfs/freebsd/usr/home/tavianator 
TARGET
  SOURCE                      FSTYPE OPTIONS
/ /dev/mapper/cryptslash1[/@] btrfs  rw,relatime,ssd,discard=async,space_cache=v2,subvolid=261,subvol=/@
root@tachyon ~ # exportfs -v
/srv/nfs        100.101.179.2/32(sync,wdelay,hide,no_subtree_check,fsid=0,sec=sys,rw,secure,no_root_squash,no_all_squash)
/srv/nfs        100.114.24.115/32(sync,wdelay,hide,no_subtree_check,fsid=0,sec=sys,rw,secure,no_root_squash,no_all_squash)
/srv/nfs/freebsd
                100.101.179.2/32(sync,wdelay,nohide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/srv/nfs/freebsd
                100.114.24.115/32(sync,wdelay,nohide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
tavianator@muon $ uname -a
FreeBSD muon 13.2-RELEASE FreeBSD 13.2-RELEASE releng/13.2-n254617-525ecfdad597 GENERIC amd64
tavianator@muon $ mount | grep nfs,
100.107.249.85:/freebsd/usr/home/tavianator on /usr/home/tavianator (nfs, nfsv4acls)
Tavian Barnes
  • 851
  • 1
  • 6
  • 14

1 Answers1

2

From looking at a packet capture in Wireshark, it appears this is a bug in the Linux server, not the FreeBSD client.

I believe this is a bug in Linux kernel commit e377a3e698fb, first included in version 5.18. That commit adds support for reporting TIME_CREATE aka birth time. After that commit, the code that writes out file timestamps looks like this:

    if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
        p = xdr_reserve_space(xdr, 12);
        if (!p)
            goto out_resource;
        p = xdr_encode_hyper(p, (s64)stat.atime.tv_sec);
        *p++ = cpu_to_be32(stat.atime.tv_nsec);
    }
    if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
        ...
    }
    if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
        ...
    }
    if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
        ...
    }
    if (bmval1 & FATTR4_WORD1_TIME_CREATE) {
        ...
    }

I believe the way the protocol works is that the times are written in an order that's supposed to match the bmval1 bitmask. In this case, the order would be [ACCESS, METADATA, MODIFY, CREATE]. However, let's look at the actual bit flag values:

#define FATTR4_WORD1_TIME_ACCESS        (1UL << 15)
#define FATTR4_WORD1_TIME_ACCESS_SET    (1UL << 16)
#define FATTR4_WORD1_TIME_BACKUP        (1UL << 17)
#define FATTR4_WORD1_TIME_CREATE        (1UL << 18)
#define FATTR4_WORD1_TIME_DELTA         (1UL << 19)
#define FATTR4_WORD1_TIME_METADATA      (1UL << 20)
#define FATTR4_WORD1_TIME_MODIFY        (1UL << 21)
#define FATTR4_WORD1_TIME_MODIFY_SET    (1UL << 22)

So the order they should be written in is [ACCESS, CREATE, METADATA, MODIFY]. This matches what I'm seeing:

Linux FreeBSD
ACCESS 1991-12-14 00:00:00.000000000 Dec 14 00:00:00 1991
CREATE 2023-06-23 15:19:21.718006131 Jun 23 15:19:24 2023
METADATA 2023-06-23 15:19:24.718067075 Dec 15 00:00:00 1991
MODIFY 1991-12-15 00:00:00.000000000 Jun 23 15:19:21 2023
Tavian Barnes
  • 851
  • 1
  • 6
  • 14