]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
fuse2fs: fix relatime comparisons
authorDarrick J. Wong <djwong@kernel.org>
Mon, 7 Jul 2025 16:05:25 +0000 (09:05 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 31 Jul 2025 14:41:55 +0000 (10:41 -0400)
generic/192 fails like this even before we start adding iomap code:

    --- tests/generic/192.out   2025-04-30 16:20:44.512675591 -0700
    +++ tests/generic/192.out.bad    2025-07-06 22:26:11.666015735 -0700
    @@ -1,5 +1,6 @@
     QA output created by 192
     sleep for 5 seconds
     test
    -delta1 is in range
    +delta1 has value of 0
    +delta1 is NOT in range 5 .. 7
     delta2 is in range

The cause of this regression is that the timestamp comparisons account
only for seconds, not nanoseconds.  If a write came in 100ms after the
last read but still in the same second, then we fail to update atime on
a subsequent read.

Fix this by converting the timespecs to doubles so that we can include
the nanoseconds component, and then perform the comparison in floating
point mode.

Cc: linux-ext4@vger.kernel.org # v1.43
Fixes: 81cbf1ef4f5dab ("misc: add fuse2fs, a FUSE server for e2fsprogs")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Link: https://lore.kernel.org/r/20250707160525.GC2672022@frogsfrogsfrogs
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
misc/fuse2fs.c

index ab3efea66d3def64010922bb91119e2d8bde1fc7..b7201f7c8ed18542eaeddcae51623182da520006 100644 (file)
@@ -461,6 +461,7 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino)
        errcode_t err;
        struct ext2_inode_large inode, *pinode;
        struct timespec atime, mtime, now;
+       double datime, dmtime, dnow;
 
        if (!(fs->flags & EXT2_FLAG_RW))
                return 0;
@@ -472,11 +473,17 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino)
        EXT4_INODE_GET_XTIME(i_atime, &atime, pinode);
        EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);
        get_now(&now);
+
+       datime = atime.tv_sec + ((double)atime.tv_nsec / 1000000000);
+       dmtime = mtime.tv_sec + ((double)mtime.tv_nsec / 1000000000);
+       dnow = now.tv_sec + ((double)now.tv_nsec / 1000000000);
+
        /*
         * If atime is newer than mtime and atime hasn't been updated in thirty
-        * seconds, skip the atime update.  Same idea as Linux "relatime".
+        * seconds, skip the atime update.  Same idea as Linux "relatime".  Use
+        * doubles to account for nanosecond resolution.
         */
-       if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30)
+       if (datime >= dmtime && datime >= dnow - 30)
                return 0;
        EXT4_INODE_SET_XTIME(i_atime, &now, &inode);