]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: add mnt_fs_fetch_ids() and populate uniq_id for utab
authorKarel Zak <kzak@redhat.com>
Thu, 25 Jun 2026 10:32:31 +0000 (12:32 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 29 Jun 2026 09:08:58 +0000 (11:08 +0200)
Add mnt_fs_fetch_ids() helper that fetches mount IDs from the kernel
via statx(). It prefers STATX_MNT_ID_UNIQUE and falls back to the old
STATX_MNT_ID on older kernels. Accepts an optional fd argument; when
fd < 0 it falls back to path-based lookup via fs->target.

Use it in hook_create_mount() (new mount API) with fd_tree for robust
fd-based ID, and in hook_mount() (legacy mount(2)) after
reopen_target_fd with fd_target when available.

This ensures utab entries contain UNIQID, which is needed for reliable
utab merging with listmount-based tables.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/fs.c
libmount/src/hook_mount.c
libmount/src/hook_mount_legacy.c
libmount/src/mountP.h

index a0d18a4f986cf9ba9d59dd552b7701e8a1144e43..8da98cc849e663e575426eed3c0d7024cbe38cd0 100644 (file)
@@ -1533,6 +1533,45 @@ int mnt_fs_set_uniq_id(struct libmnt_fs *fs, uint64_t id)
        return 0;
 }
 
+/*
+ * Fetch mount IDs from kernel via statx(). Prefers unique ID, falls back
+ * to old ID on old kernels. Uses @fd (AT_EMPTY_PATH) if >= 0, otherwise
+ * uses fs->target path.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int mnt_fs_fetch_ids(struct libmnt_fs *fs, int fd)
+{
+       uint64_t uniq_id = 0;
+       int id = 0, rc;
+
+       if (!fs)
+               return -EINVAL;
+       if (fd < 0 && !mnt_fs_get_target(fs))
+               return -EINVAL;
+
+       if (fd >= 0)
+               rc = mnt_id_from_fd(fd, &uniq_id, NULL);
+       else
+               rc = mnt_id_from_path(mnt_fs_get_target(fs), &uniq_id, NULL);
+
+       if (rc == 0 && uniq_id > 0) {
+               fs->uniq_id = uniq_id;
+               return 0;
+       }
+
+       /* fallback to old mount ID */
+       if (fd >= 0)
+               rc = mnt_id_from_fd(fd, NULL, &id);
+       else
+               rc = mnt_id_from_path(mnt_fs_get_target(fs), NULL, &id);
+
+       if (rc == 0)
+               fs->id = id;
+
+       return rc;
+}
+
 /**
  * mnt_fs_get_parent_id:
  * @fs: /proc/self/mountinfo entry
index 1dab62c68798688ecef32736598cd170b2c13955..acd0df027acdc2969728efbdbdea427b776ddfb6 100644 (file)
@@ -323,24 +323,22 @@ static int hook_create_mount(struct libmnt_context *cxt,
                /* cleanup after fail (libmount may only try the FS type) */
                close_sysapi_fds(api);
 
-#if defined(HAVE_STATX) && defined(HAVE_STRUCT_STATX) && defined(HAVE_STRUCT_STATX_STX_MNT_ID)
        if (!rc && cxt->fs) {
-               struct statx st;
-
-               rc = statx(api->fd_tree, "", AT_EMPTY_PATH, STATX_MNT_ID, &st);
-               if (rc == 0) {
-                       cxt->fs->id = (int) st.stx_mnt_id;
-                       if (cxt->update) {
-                               struct libmnt_fs *fs = mnt_update_get_fs(cxt->update);
-                               if (fs)
-                                       fs->id = cxt->fs->id;
+               mnt_fs_fetch_ids(cxt->fs, api->fd_tree);
+
+               if ((cxt->fs->id || cxt->fs->uniq_id) && cxt->update) {
+                       struct libmnt_fs *fs = mnt_update_get_fs(cxt->update);
+                       if (fs) {
+                               fs->id = cxt->fs->id;
+                               fs->uniq_id = cxt->fs->uniq_id;
                        }
                }
        }
-#endif
 
 done:
-       DBG_OBJ(HOOK, hs, ul_debug("create FS done [rc=%d, id=%d]", rc, cxt->fs ? cxt->fs->id : -1));
+       DBG_OBJ(HOOK, hs, ul_debug("create FS done [rc=%d, id=%d, uniq=%" PRIu64 "]",
+                               rc, cxt->fs ? cxt->fs->id : -1,
+                               cxt->fs ? cxt->fs->uniq_id : (uint64_t) 0));
        return rc;
 }
 
index 86b1c9f06282edf23136fc027a97a21c578f7abb..0327db4c2b1ef398146c53a3662fd28f1c7a3bf5 100644 (file)
@@ -251,10 +251,25 @@ static int hook_mount(struct libmnt_context *cxt,
        else
                mnt_fs_mark_attached(cxt->fs);
 
+       cxt->syscall_status = 0;
+
        /* re-open to point to the mounted filesystem root */
        rc = mnt_context_reopen_target_fd(cxt);
 
-       cxt->syscall_status = 0;
+       /* Fetch mount IDs for utab. Note that IDs are not 100% robust
+        * with mount(2) -- another process could overmount the target
+        * between mount(2) and our statx() call. */
+       if (rc == 0 && cxt->fs && cxt->update && mnt_update_is_ready(cxt->update)) {
+               mnt_fs_fetch_ids(cxt->fs, cxt->fd_target);
+               if (cxt->fs->id || cxt->fs->uniq_id) {
+                       struct libmnt_fs *fs = mnt_update_get_fs(cxt->update);
+                       if (fs) {
+                               fs->id = cxt->fs->id;
+                               fs->uniq_id = cxt->fs->uniq_id;
+                       }
+               }
+       }
+
        return rc;
 }
 
index 01af14f3fe14507678ce9d239468ade89c29644a..3f5a93d9459dce799baaa7d2697622bb6ef71c6e 100644 (file)
@@ -140,6 +140,7 @@ extern int mnt_tmptgt_unshare(int *old_ns_fd);
 extern int mnt_tmptgt_cleanup(int old_ns_fd);
 
 extern int mnt_id_from_fd(int fd, uint64_t *uniq_id, int *id);
+extern int mnt_fs_fetch_ids(struct libmnt_fs *fs, int fd);
 
 /* tab.c */
 extern int is_mountinfo(struct libmnt_table *tb);