add unique mount ID
authorMiklos Szeredi <mszeredi@redhat.com>
Wed, 25 Oct 2023 14:01:59 +0000 (16:01 +0200)
committerChristian Brauner <brauner@kernel.org>
Sat, 18 Nov 2023 13:56:16 +0000 (14:56 +0100)
If a mount is released then its mnt_id can immediately be reused.  This is
bad news for user interfaces that want to uniquely identify a mount.

Implementing a unique mount ID is trivial (use a 64bit counter).
Unfortunately userspace assumes 32bit size and would overflow after the
counter reaches 2^32.

Introduce a new 64bit ID alongside the old one.  Initialize the counter to
2^32, this guarantees that the old and new IDs are never mixed up.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://lore.kernel.org/r/20231025140205.3586473-2-mszeredi@redhat.com
Reviewed-by: Ian Kent <raven@themaw.net>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/mount.h
fs/namespace.c
fs/stat.c
include/uapi/linux/stat.h

index 130c07c..a14f762 100644 (file)
@@ -72,7 +72,8 @@ struct mount {
        struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
        __u32 mnt_fsnotify_mask;
 #endif
-       int mnt_id;                     /* mount identifier */
+       int mnt_id;                     /* mount identifier, reused */
+       u64 mnt_id_unique;              /* mount ID unique until reboot */
        int mnt_group_id;               /* peer group identifier */
        int mnt_expiry_mark;            /* true if marked for expiry */
        struct hlist_head mnt_pins;
index fbf0e59..0bcba81 100644 (file)
@@ -68,6 +68,9 @@ static u64 event;
 static DEFINE_IDA(mnt_id_ida);
 static DEFINE_IDA(mnt_group_ida);
 
+/* Don't allow confusion with old 32bit mount ID */
+static atomic64_t mnt_id_ctr = ATOMIC64_INIT(1ULL << 32);
+
 static struct hlist_head *mount_hashtable __ro_after_init;
 static struct hlist_head *mountpoint_hashtable __ro_after_init;
 static struct kmem_cache *mnt_cache __ro_after_init;
@@ -131,6 +134,7 @@ static int mnt_alloc_id(struct mount *mnt)
        if (res < 0)
                return res;
        mnt->mnt_id = res;
+       mnt->mnt_id_unique = atomic64_inc_return(&mnt_id_ctr);
        return 0;
 }
 
index 24bb020..e44f062 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -243,8 +243,13 @@ retry:
 
        error = vfs_getattr(&path, stat, request_mask, flags);
 
-       stat->mnt_id = real_mount(path.mnt)->mnt_id;
-       stat->result_mask |= STATX_MNT_ID;
+       if (request_mask & STATX_MNT_ID_UNIQUE) {
+               stat->mnt_id = real_mount(path.mnt)->mnt_id_unique;
+               stat->result_mask |= STATX_MNT_ID_UNIQUE;
+       } else {
+               stat->mnt_id = real_mount(path.mnt)->mnt_id;
+               stat->result_mask |= STATX_MNT_ID;
+       }
 
        if (path.mnt->mnt_root == path.dentry)
                stat->attributes |= STATX_ATTR_MOUNT_ROOT;
index 7cab2c6..2f2ee82 100644 (file)
@@ -154,6 +154,7 @@ struct statx {
 #define STATX_BTIME            0x00000800U     /* Want/got stx_btime */
 #define STATX_MNT_ID           0x00001000U     /* Got stx_mnt_id */
 #define STATX_DIOALIGN         0x00002000U     /* Want/got direct I/O alignment info */
+#define STATX_MNT_ID_UNIQUE    0x00004000U     /* Want/got extended stx_mount_id */
 
 #define STATX__RESERVED                0x80000000U     /* Reserved for future struct statx expansion */