Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

add unique mount ID

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>

authored by

Miklos Szeredi and committed by
Christian Brauner
98d2b430 b85ea95d

+14 -3
+2 -1
fs/mount.h
··· 72 72 struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks; 73 73 __u32 mnt_fsnotify_mask; 74 74 #endif 75 - int mnt_id; /* mount identifier */ 75 + int mnt_id; /* mount identifier, reused */ 76 + u64 mnt_id_unique; /* mount ID unique until reboot */ 76 77 int mnt_group_id; /* peer group identifier */ 77 78 int mnt_expiry_mark; /* true if marked for expiry */ 78 79 struct hlist_head mnt_pins;
+4
fs/namespace.c
··· 68 68 static DEFINE_IDA(mnt_id_ida); 69 69 static DEFINE_IDA(mnt_group_ida); 70 70 71 + /* Don't allow confusion with old 32bit mount ID */ 72 + static atomic64_t mnt_id_ctr = ATOMIC64_INIT(1ULL << 32); 73 + 71 74 static struct hlist_head *mount_hashtable __ro_after_init; 72 75 static struct hlist_head *mountpoint_hashtable __ro_after_init; 73 76 static struct kmem_cache *mnt_cache __ro_after_init; ··· 134 131 if (res < 0) 135 132 return res; 136 133 mnt->mnt_id = res; 134 + mnt->mnt_id_unique = atomic64_inc_return(&mnt_id_ctr); 137 135 return 0; 138 136 } 139 137
+7 -2
fs/stat.c
··· 243 243 244 244 error = vfs_getattr(&path, stat, request_mask, flags); 245 245 246 - stat->mnt_id = real_mount(path.mnt)->mnt_id; 247 - stat->result_mask |= STATX_MNT_ID; 246 + if (request_mask & STATX_MNT_ID_UNIQUE) { 247 + stat->mnt_id = real_mount(path.mnt)->mnt_id_unique; 248 + stat->result_mask |= STATX_MNT_ID_UNIQUE; 249 + } else { 250 + stat->mnt_id = real_mount(path.mnt)->mnt_id; 251 + stat->result_mask |= STATX_MNT_ID; 252 + } 248 253 249 254 if (path.mnt->mnt_root == path.dentry) 250 255 stat->attributes |= STATX_ATTR_MOUNT_ROOT;
+1
include/uapi/linux/stat.h
··· 154 154 #define STATX_BTIME 0x00000800U /* Want/got stx_btime */ 155 155 #define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */ 156 156 #define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */ 157 + #define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */ 157 158 158 159 #define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ 159 160