]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
xstatx_full(): add flag to acquire STATX_MNT_ID_UNIQUE if we can, with fallback. 40825/head
authorLennart Poettering <lennart@amutable.com>
Wed, 25 Feb 2026 13:16:47 +0000 (14:16 +0100)
committerLennart Poettering <lennart@amutable.com>
Tue, 3 Mar 2026 07:49:23 +0000 (08:49 +0100)
src/basic/chase.c
src/basic/dirent-util.c
src/basic/mountpoint-util.c
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/xattr-util.c
src/mountfsd/mountwork.c
src/shared/find-esp.c
src/tmpfiles/tmpfiles.c

index 2243b129729a110a2bab5c8c008d21f3c1882771..82946eae5f199ab4c9dfb8a7b175dc926ceda209 100644 (file)
@@ -150,7 +150,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         struct statx root_stx, stx;
         bool need_absolute = false; /* allocate early to avoid compiler warnings around goto */
         const char *todo;
-        unsigned mask = STATX_TYPE|STATX_UID|STATX_INO|STATX_MNT_ID;
+        unsigned mask = STATX_TYPE|STATX_UID|STATX_INO;
         int r;
 
         assert(!FLAGS_SET(flags, CHASE_PREFIX_ROOT));
@@ -263,7 +263,14 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                         if (fd < 0)
                                 return -errno;
 
-                        r = xstatx(fd, /* path= */ NULL, /* flags= */ 0, mask, &stx);
+                        r = xstatx_full(fd,
+                                        /* path= */ NULL,
+                                        /* statx_flags= */ 0,
+                                        XSTATX_MNT_ID_BEST,
+                                        mask,
+                                        /* optional_mask= */ 0,
+                                        /* mandatory_attributes= */ 0,
+                                        &stx);
                         if (r < 0)
                                 return r;
 
@@ -316,7 +323,14 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         if (fd < 0)
                 return -errno;
 
-        r = xstatx(fd, /* path= */ NULL, /* flags= */ 0, mask, &stx);
+        r = xstatx_full(fd,
+                        /* path= */ NULL,
+                        /* statx_flags= */ 0,
+                        XSTATX_MNT_ID_BEST,
+                        mask,
+                        /* optional_mask= */ 0,
+                        /* mandatory_attributes= */ 0,
+                        &stx);
         if (r < 0)
                 return r;
         root_stx = stx; /* remember stat data of the root, so that we can recognize it later */
@@ -399,7 +413,14 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                         if (fd_parent < 0)
                                 return -errno;
 
-                        r = xstatx(fd_parent, /* path= */ NULL, /* flags= */ 0, mask, &stx_parent);
+                        r = xstatx_full(fd_parent,
+                                        /* path= */ NULL,
+                                        /* statx_flags= */ 0,
+                                        XSTATX_MNT_ID_BEST,
+                                        mask,
+                                        /* optional_mask= */ 0,
+                                        /* mandatory_attributes= */ 0,
+                                        &stx_parent);
                         if (r < 0)
                                 return r;
 
@@ -465,7 +486,14 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                                 if (fd_grandparent < 0)
                                         return -errno;
 
-                                r = xstatx(fd_grandparent, /* path= */ NULL, /* flags= */ 0, mask, &stx_grandparent);
+                                r = xstatx_full(fd_grandparent,
+                                                /* path= */ NULL,
+                                                /* statx_flags= */ 0,
+                                                XSTATX_MNT_ID_BEST,
+                                                mask,
+                                                /* optional_mask= */ 0,
+                                                /* mandatory_attributes= */ 0,
+                                                &stx_grandparent);
                                 if (r < 0)
                                         return r;
 
@@ -519,7 +547,14 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                 }
 
                 /* ... and then check what it actually is. */
-                r = xstatx(child, /* path= */ NULL, /* flags= */ 0, mask, &stx_child);
+                r = xstatx_full(child,
+                                /* path= */ NULL,
+                                /* statx_flags= */ 0,
+                                XSTATX_MNT_ID_BEST,
+                                mask,
+                                /* optional_mask= */ 0,
+                                /* mandatory_attributes= */ 0,
+                                &stx_child);
                 if (r < 0)
                         return r;
 
@@ -557,7 +592,14 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                                 if (fd < 0)
                                         return fd;
 
-                                r = xstatx(fd, /* path= */ NULL, /* flags= */ 0, mask, &stx);
+                                r = xstatx_full(fd,
+                                                /* path= */ NULL,
+                                                /* statx_flags= */ 0,
+                                                XSTATX_MNT_ID_BEST,
+                                                mask,
+                                                /* optional_mask= */ 0,
+                                                /* mandatory_attributes= */ 0,
+                                                &stx);
                                 if (r < 0)
                                         return r;
 
index a1508747777a0020d7cb3bb47755931c0f850663..91a7040e408e7f39dfe619eba824e4d6d0beea91 100644 (file)
@@ -27,6 +27,7 @@ int dirent_ensure_type(int dir_fd, struct dirent *de) {
         r = xstatx_full(dir_fd,
                         de->d_name,
                         AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
+                        /* xstatx_flags= */ 0,
                         /* mandatory_mask= */ STATX_TYPE,
                         /* optional_mask= */ STATX_INO,
                         /* mandatory_attributes= */ 0,
index 06d4d4450a22db6568880e2dae4c5dde0364bf77..79b51cb099fcde15c03697e8fe5836286e1b2786 100644 (file)
@@ -250,6 +250,7 @@ int is_mount_point_at(int dir_fd, const char *path, int flags) {
                         at_flags_normalize_nofollow(flags) |
                         AT_NO_AUTOMOUNT |            /* don't trigger automounts – mounts are a local concept, hence no need to trigger automounts to determine STATX_ATTR_MOUNT_ROOT */
                         AT_STATX_DONT_SYNC,          /* don't go to the network for this – for similar reasons */
+                        /* xstatx_flags = */ 0,
                         STATX_TYPE|STATX_INO,
                         /* optional_mask = */ 0,
                         STATX_ATTR_MOUNT_ROOT,
index 7f065b5c7f03b64c5e033589ee2e079f2539c959..ef39562992ca0ef282ab472036e24a3e16d745a4 100644 (file)
@@ -328,7 +328,8 @@ DEFINE_STATX_BITS_TO_STRING(statx_attributes, uint64_t, statx_attribute_to_name,
 
 int xstatx_full(int fd,
                 const char *path,
-                int flags,
+                int statx_flags,
+                XStatXFlags xstatx_flags,
                 unsigned mandatory_mask,
                 unsigned optional_mask,
                 uint64_t mandatory_attributes,
@@ -344,10 +345,13 @@ int xstatx_full(int fd,
          * 3. Takes separate mandatory and optional mask params, plus mandatory attributes.
          *    Returns -EUNATCH if statx() does not return all masks specified as mandatory,
          *    > 0 if all optional masks are supported, 0 otherwise.
+         * 4. Supports a new flag XSTATX_MNT_ID_BEST which acquires STATX_MNT_ID_UNIQUE if available and
+         *    STATX_MNT_ID if not.
          */
 
         assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT));
         assert((mandatory_mask & optional_mask) == 0);
+        assert(!FLAGS_SET(xstatx_flags, XSTATX_MNT_ID_BEST) || !((mandatory_mask|optional_mask) & (STATX_MNT_ID|STATX_MNT_ID_UNIQUE)));
         assert(ret);
 
         _cleanup_free_ char *p = NULL;
@@ -355,12 +359,21 @@ int xstatx_full(int fd,
         if (r < 0)
                 return r;
 
-        if (statx(fd, strempty(path),
-                  flags|(isempty(path) ? AT_EMPTY_PATH : 0),
-                  mandatory_mask|optional_mask,
+        unsigned request_mask = mandatory_mask|optional_mask;
+        if (FLAGS_SET(xstatx_flags, XSTATX_MNT_ID_BEST))
+                request_mask |= STATX_MNT_ID|STATX_MNT_ID_UNIQUE;
+
+        if (statx(fd,
+                  strempty(path),
+                  statx_flags|(isempty(path) ? AT_EMPTY_PATH : 0),
+                  request_mask,
                   &sx) < 0)
                 return negative_errno();
 
+        if (FLAGS_SET(xstatx_flags, XSTATX_MNT_ID_BEST) &&
+            !(sx.stx_mask & (STATX_MNT_ID|STATX_MNT_ID_UNIQUE)))
+                return log_debug_errno(SYNTHETIC_ERRNO(EUNATCH), "statx() did not return either STATX_MNT_ID or STATX_MNT_ID_UNIQUE.");
+
         if (!FLAGS_SET(sx.stx_mask, mandatory_mask)) {
                 if (DEBUG_LOGGING) {
                         _cleanup_free_ char *mask_str = statx_mask_to_string(mandatory_mask & ~sx.stx_mask);
index 230535aad41ca9c757f088878be8a9abba7b4b86..c261014cd2953fed1301eb4ff4a789c9ef30a981 100644 (file)
@@ -47,9 +47,14 @@ static inline int null_or_empty_path(const char *fn) {
         return null_or_empty_path_with_root(fn, NULL);
 }
 
+typedef enum XStatXFlags {
+        XSTATX_MNT_ID_BEST = 1 << 0, /* Like STATX_MNT_ID_UNIQUE if available, STATX_MNT_ID otherwise */
+} XStatXFlags;
+
 int xstatx_full(int fd,
                 const char *path,
-                int flags,
+                int statx_flags,
+                XStatXFlags xstatx_flags,
                 unsigned mandatory_mask,
                 unsigned optional_mask,
                 uint64_t mandatory_attributes,
@@ -58,11 +63,11 @@ int xstatx_full(int fd,
 static inline int xstatx(
                 int fd,
                 const char *path,
-                int flags,
+                int statx_flags,
                 unsigned mandatory_mask,
                 struct statx *ret) {
 
-        return xstatx_full(fd, path, flags, mandatory_mask, 0, 0, ret);
+        return xstatx_full(fd, path, statx_flags, 0, mandatory_mask, 0, 0, ret);
 }
 
 int fd_is_read_only_fs(int fd);
index 68ee83d899edef88fe1bf2d2d842d1003adf366c..e77d0bc8e84efe4a5677cf2572442db400a4fde8 100644 (file)
@@ -429,11 +429,13 @@ int getcrtime_at(
          * concept is useful for determining how "old" a file really is, and hence using the older of the two makes
          * most sense. */
 
-        r = xstatx_full(fd, path,
+        r = xstatx_full(fd,
+                        path,
                         at_flags_normalize_nofollow(at_flags)|AT_STATX_DONT_SYNC,
-                        /* mandatory_mask = */ 0,
+                        /* xstatx_flags= */ 0,
+                        /* mandatory_mask= */ 0,
                         STATX_BTIME,
-                        /* mandatory_attributes = */ 0,
+                        /* mandatory_attributes= */ 0,
                         &sx);
         if (r > 0 && sx.stx_btime.tv_sec != 0) /* > 0: all optional masks are supported */
                 a = statx_timestamp_load(&sx.stx_btime);
index 54d92b5585614e6f0ac9eeb3b20e2fc1cab55500..922bcb1b18995be2a97507b5bc3a8c77457fb465 100644 (file)
@@ -866,7 +866,8 @@ static DirectoryOwnership validate_directory_fd(
         r = xstatx_full(fd,
                         /* path= */ NULL,
                         AT_EMPTY_PATH,
-                        /* mandatory_mask= */ STATX_TYPE|STATX_UID|STATX_MNT_ID|STATX_INO,
+                        /* xstatx_flags= */ XSTATX_MNT_ID_BEST,
+                        /* mandatory_mask= */ STATX_TYPE|STATX_UID|STATX_INO,
                         /* optional_mask= */ 0,
                         /* mandatory_attributes= */ STATX_ATTR_MOUNT_ROOT,
                         &stx);
@@ -933,7 +934,8 @@ static DirectoryOwnership validate_directory_fd(
                 r = xstatx_full(new_parent_fd,
                                 /* path= */ NULL,
                                 AT_EMPTY_PATH,
-                                /* mandatory_mask= */ STATX_UID|STATX_MNT_ID|STATX_INO,
+                                /* xstatx_flags= */ XSTATX_MNT_ID_BEST,
+                                /* mandatory_mask= */ STATX_UID|STATX_INO,
                                 /* optional_mask= */ 0,
                                 /* mandatory_attributes= */ STATX_ATTR_MOUNT_ROOT,
                                 &new_stx);
index 3ba9b8a4b601b722483bf90652962f84952425a4..a2a2093fafb935a344d4807ba7823faf9b9a0498 100644 (file)
@@ -287,6 +287,7 @@ static int verify_fsroot_dir(
 
         r = xstatx_full(dir_fd, f,
                         AT_SYMLINK_NOFOLLOW,
+                        /* xstatx_flags= */ 0,
                         STATX_TYPE|STATX_INO,
                         /* optional_mask = */ 0,
                         STATX_ATTR_MOUNT_ROOT,
index 090884b228303e42411dcbc8f0ef735e2ea1821d..0d62b847b65cbc5e6caa86ce188ff0c135bec912 100644 (file)
@@ -586,9 +586,12 @@ static int opendir_and_stat(
                 return 0;
         }
 
-        r = xstatx_full(dirfd(d), /* path = */ NULL, AT_EMPTY_PATH,
+        r = xstatx_full(dirfd(d),
+                        /* path= */ NULL,
+                        AT_EMPTY_PATH,
+                        /* xstatx_flags= */ 0,
                         STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME,
-                        /* optional_mask = */ 0,
+                        /* optional_mask= */ 0,
                         STATX_ATTR_MOUNT_ROOT,
                         &sx);
         if (r < 0)
@@ -687,6 +690,7 @@ static int dir_cleanup(
                 struct statx sx;
                 r = xstatx_full(dirfd(d), de->d_name,
                                 AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
+                                /* xstatx_flags= */ 0,
                                 STATX_TYPE|STATX_MODE|STATX_UID,
                                 STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
                                 STATX_ATTR_MOUNT_ROOT,