The current test in nap.h tries to gauge the minimum delay that results
in a timestamp change when successively writing to a file.

There are some proposed changes [1] to track finer-grained timestamps in
the Linux kernel that will break the assumptions that nap() uses to
gauge the delay. In particular, writing to a file will almost always
show a change in the timestamp now, so usually this method will settle
on a delay of 1ns.

Switch this code over to use file creation of two files to gauge the
delay. Since that is operating on two different files, it should still
be possible to gauge the coarse-grained timer tick from that.

[1]: 
https://lore.kernel.org/linux-fsdevel/20240626-mgtime-v1-0-a189352d0...@kernel.org/

Signed-off-by: Jeff Layton <jlay...@kernel.org>
---
Failure of the test-stat-time test is what triggered us to revert the
multigrain timestamp series from the Linux kernel last October.  With
that failure, we'd sometimes see timestamps showing files being modified
in reverse order (if one got a fine-grained and another got a
coarse-grained timestamp).  That problem has now been addressed, but
test-stat-time still fails without this change.
---
 ChangeLog   |  5 ++++
 tests/nap.h | 84 +++++++++++++++++++++----------------------------------------
 2 files changed, 33 insertions(+), 56 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a9453b0b4513..6524d717cf7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2024-06-28  Jeff Layton  <jlay...@kernel.org>
+       * tests/nap.h: change the method used to gauge the coarse-grained
+       timestamp to use creation of two files instead of writes to a
+       single file.
+
 2024-06-28  Bruno Haible  <br...@clisp.org>
 
        time: Fix test failure on FreeBSD.
diff --git a/tests/nap.h b/tests/nap.h
index cf7d998b800e..323df6264a02 100644
--- a/tests/nap.h
+++ b/tests/nap.h
@@ -31,10 +31,8 @@
 # endif
 
 /* Name of the witness file.  */
-#define TEMPFILE BASE "nap.tmp"
-
-/* File descriptor used for the witness file.  */
-static int nap_fd = -1;
+#define TEMPFILE1 BASE "nap1.tmp"
+#define TEMPFILE2 BASE "nap2.tmp"
 
 /* Return A - B, in ns.
    Return 0 if the true result would be negative.
@@ -62,56 +60,46 @@ diff_timespec (struct timespec a, struct timespec b)
   return sdiff;
 }
 
-/* If DO_WRITE, bump the modification time of the file designated by NAP_FD.
-   Then fetch the new STAT information of NAP_FD.  */
-static void
-nap_get_stat (struct stat *st, int do_write)
+void clear_tempfiles(void)
 {
-  if (do_write)
-    {
-      ASSERT (write (nap_fd, "\n", 1) == 1);
-#if defined _WIN32 || defined __CYGWIN__
-      /* On Windows, the modification times are not changed until NAP_FD
-         is closed. See
-         
<https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile>
 */
-      close (nap_fd);
-      nap_fd = open (TEMPFILE, O_RDWR, 0600);
-      ASSERT (nap_fd != -1);
-      lseek (nap_fd, 0, SEEK_END);
-#endif
-    }
-  ASSERT (fstat (nap_fd, st) == 0);
+       unlink(TEMPFILE1);
+       unlink(TEMPFILE2);
 }
 
 /* Given a file whose descriptor is FD, see whether delaying by DELAY
    nanoseconds causes a change in a file's mtime.
    OLD_ST is the file's status, recently gotten.  */
 static bool
-nap_works (int delay, struct stat old_st)
+nap_works (int delay)
 {
-  struct stat st;
+  struct stat st1, st2;
   struct timespec delay_spec;
+  int fd1, fd2;
+  int ret;
+
+  ret = unlink (TEMPFILE1);
+  ASSERT(ret == 0 || errno == ENOENT);
+  ret = unlink (TEMPFILE2);
+  ASSERT(ret == 0 || errno == ENOENT);
+
   delay_spec.tv_sec = delay / 1000000000;
   delay_spec.tv_nsec = delay % 1000000000;
-  ASSERT (nanosleep (&delay_spec, 0) == 0);
-  nap_get_stat (&st, 1);
 
-  if (diff_timespec (get_stat_mtime (&st), get_stat_mtime (&old_st)))
+  ASSERT ((fd1 = creat (TEMPFILE1, 0600)) != -1);
+  close(fd1);
+  ASSERT (nanosleep (&delay_spec, 0) == 0);
+  ASSERT ((fd2 = creat (TEMPFILE2, 0600)) != -1);
+  close(fd2);
+  ASSERT (stat (TEMPFILE1, &st1) != -1);
+  ASSERT (stat (TEMPFILE2, &st2) != -1);
+  ASSERT (unlink (TEMPFILE1) == 0);
+  ASSERT (unlink (TEMPFILE2) == 0);
+
+  if (diff_timespec (get_stat_mtime (&st2), get_stat_mtime (&st1)))
     return true;
-
   return false;
 }
 
-static void
-clear_temp_file (void)
-{
-  if (0 <= nap_fd)
-    {
-      ASSERT (close (nap_fd) != -1);
-      ASSERT (unlink (TEMPFILE) != -1);
-    }
-}
-
 /* Sleep long enough to notice a timestamp difference on the file
    system in the current directory.  Use an adaptive approach, trying
    to find the smallest delay which works on the current file system
@@ -122,28 +110,12 @@ clear_temp_file (void)
 static void
 nap (void)
 {
-  struct stat old_st;
   static int delay = 1;
 
-  if (-1 == nap_fd)
-    {
-      atexit (clear_temp_file);
-      ASSERT ((nap_fd = creat (TEMPFILE, 0600)) != -1);
-      nap_get_stat (&old_st, 0);
-    }
-  else
-    {
-      ASSERT (0 <= nap_fd);
-      nap_get_stat (&old_st, 1);
-    }
-
-  if (1 < delay)
-    delay = delay / 2;  /* Try half of the previous delay.  */
-  ASSERT (0 < delay);
-
+  atexit(clear_tempfiles);
   for (;;)
     {
-      if (nap_works (delay, old_st))
+      if (nap_works (delay))
         return;
       if (delay <= (2147483647 - 1) / 2)
         {

---
base-commit: 1066dc9c0bc4ffa65fe117cf055a346482f03b1e
change-id: 20240612-master-432eef551152

Best regards,
-- 
Jeff Layton <jlay...@kernel.org>


Reply via email to