fts: introduce FTS_NOATIME
authorEric Blake <eblake@redhat.com>
Thu, 7 Jul 2011 17:37:37 +0000 (11:37 -0600)
committerEric Blake <eblake@redhat.com>
Fri, 8 Jul 2011 17:15:45 +0000 (11:15 -0600)
This gives clients the option to try a non-invasive traversal,
where merely visiting a directory does not update its timestamp,
where such is supported by the kernel.

Note that this is best-effort.  FTS_NOATIME is silently ignored
on systems that lack O_NOATIME support - it is up to the caller
to decide whether to issue an error when the gnulib replacement
<fcntl.h> defined O_NOATIME to 0, and/or detect older Linux
kernels where O_NOATIME is defined to non-zero but has no effect.

Note that whiteout support and O_NOATIME support are currently
orthogonal: there is no way to get O_NOATIME behavior when using
__opendir2 to visit whiteouts on BSD systems.  So far, I don't
know of any system with both __opendir2 and O_NOATIME; if such
a system exists, then fts_build() needs a tweak (then again,
such a system would probably add DTF_NOATIME for __opendir2).

* lib/fts_.h (FTS_NOATIME): New bit flag.
(FTS_OPTIONMASK): Adjust.
* lib/fts.c (diropen, fts_open, fts_build): Honor it.
(fd_ring_check): Debug code unconditionally uses O_NOATIME.
Needed for findutils bug http://savannah.gnu.org/bugs/?33724

Signed-off-by: Eric Blake <eblake@redhat.com>
ChangeLog
lib/fts.c
lib/fts_.h

index 59f8bf8abacaaf56d84a5c8b0efdd9a0385e606c..39dbe487e8586c4328d0bbedb12b008a02199a42 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2011-07-08  Eric Blake  <eblake@redhat.com>
+
+       fts: introduce FTS_NOATIME
+       * lib/fts_.h (FTS_NOATIME): New bit flag.
+       (FTS_OPTIONMASK): Adjust.
+       * lib/fts.c (diropen, fts_open, fts_build): Honor it.
+       (fd_ring_check): Debug code unconditionally uses O_NOATIME.
+
 2011-07-08  Bruno Haible  <bruno@clisp.org>
 
        Tests for module 'thread'.
index d3ad1cd5785462892b706b7de144a2fb158e87ef..7210c1bbb9689dfe163826e0aa821778bdf3edc1 100644 (file)
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -349,7 +349,8 @@ internal_function
 diropen (FTS const *sp, char const *dir)
 {
   int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
-                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
+                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0)
+                    | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));
 
   int fd = (ISSET (FTS_CWDFD)
             ? openat (sp->fts_cwd_fd, dir, open_flags)
@@ -406,7 +407,8 @@ fts_open (char * const *argv,
                early, doing it here saves us the trouble of ensuring
                later (where it'd be messier) that "." can in fact
                be opened.  If not, revert to FTS_NOCHDIR mode.  */
-            int fd = open (".", O_SEARCH);
+            int fd = open (".",
+                           O_SEARCH | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));
             if (fd < 0)
               {
                 /* Even if `.' is unreadable, don't revert to FTS_NOCHDIR mode
@@ -1241,10 +1243,11 @@ fts_build (register FTS *sp, int type)
         opendirat((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD)     \
                    ? sp->fts_cwd_fd : AT_FDCWD),                \
                   file,                                         \
-                  ((ISSET(FTS_PHYSICAL)                         \
-                    && ! (ISSET(FTS_COMFOLLOW)                  \
-                          && cur->fts_level == FTS_ROOTLEVEL))  \
-                   ? O_NOFOLLOW : 0),                           \
+                  (((ISSET(FTS_PHYSICAL)                        \
+                     && ! (ISSET(FTS_COMFOLLOW)                 \
+                           && cur->fts_level == FTS_ROOTLEVEL)) \
+                    ? O_NOFOLLOW : 0)                           \
+                   | (ISSET (FTS_NOATIME) ? O_NOATIME : 0)),    \
                   &dir_fd)
 #endif
        if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
@@ -1653,7 +1656,7 @@ fd_ring_check (FTS const *sp)
       int fd = i_ring_pop (&fd_w);
       if (0 <= fd)
         {
-          int parent_fd = openat (cwd_fd, "..", O_SEARCH);
+          int parent_fd = openat (cwd_fd, "..", O_SEARCH | O_NOATIME);
           if (parent_fd < 0)
             {
               // Warn?
index 6a22becac47dae9fdbe7094fdf604a9009b7446b..fe92cfd7344f834a17b815fe57edcadcf492d5f1 100644 (file)
@@ -142,7 +142,9 @@ typedef struct {
      dirent.d_type data.  */
 # define FTS_DEFER_STAT         0x0400
 
-# define FTS_OPTIONMASK 0x07ff          /* valid user option mask */
+# define FTS_NOATIME    0x0800          /* use O_NOATIME during traversal */
+
+# define FTS_OPTIONMASK 0x0fff          /* valid user option mask */
 
 # define FTS_NAMEONLY   0x1000          /* (private) child names only */
 # define FTS_STOP       0x2000          /* (private) unrecoverable error */