From: Lennart Poettering Date: Tue, 25 Jun 2024 10:41:03 +0000 (+0200) Subject: mountpoint-util: add new helper name_to_handle_at_try_fid() X-Git-Tag: v257-rc1~1003^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=81995fbb9640a20010a8a4648db3e3c4882f2bdf;p=thirdparty%2Fsystemd.git mountpoint-util: add new helper name_to_handle_at_try_fid() Newer kernels support a new flag for name_to_handle_at(): AT_HANDLE_FID. This flag is supposed to return an identifier for an inode that we can use for checking inode identity. It's supposed to be a replacement for checking .st_ino which doesn't work anymore today because inode numbers are no longer unique on file systems (not on overlayfs, and not on btrfs for example). Hence, be a good citizen and add infrastructure to support AT_HANDLE_FID. Unfortunately that doesn't work for old kernels, hence add a fallback logic: if we can use the flag, use it. If we cannot use name_to_handle_at() without it, which might give us a good ID too. But of course tha tcan fail as well, which callers have to check. --- diff --git a/src/basic/missing_fcntl.h b/src/basic/missing_fcntl.h index 3c85befda96..1248eb7e4df 100644 --- a/src/basic/missing_fcntl.h +++ b/src/basic/missing_fcntl.h @@ -92,3 +92,7 @@ #define RAW_O_LARGEFILE 00100000 #endif #endif + +#ifndef AT_HANDLE_FID +#define AT_HANDLE_FID AT_REMOVEDIR +#endif diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index 4aecd109d35..71979d29ad5 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -13,6 +13,7 @@ #include "fileio.h" #include "filesystems.h" #include "fs-util.h" +#include "missing_fcntl.h" #include "missing_fs.h" #include "missing_mount.h" #include "missing_stat.h" @@ -62,7 +63,8 @@ int name_to_handle_at_loop( size_t n = ORIGINAL_MAX_HANDLE_SZ; - assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0); + assert(fd >= 0 || fd == AT_FDCWD); + assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH|AT_HANDLE_FID)) == 0); /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a @@ -119,6 +121,30 @@ int name_to_handle_at_loop( } } +int name_to_handle_at_try_fid( + int fd, + const char *path, + struct file_handle **ret_handle, + int *ret_mnt_id, + int flags) { + + int r; + + assert(fd >= 0 || fd == AT_FDCWD); + + /* First issues name_to_handle_at() with AT_HANDLE_FID. If this fails and this is not a fatal error + * we'll try without the flag, in order to support older kernels that didn't have AT_HANDLE_FID + * (i.e. older than Linux 6.5). */ + + r = name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags | AT_HANDLE_FID); + if (r >= 0) + return r; + if (is_name_to_handle_at_fatal_error(r)) + return r; + + return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID); +} + static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mnt_id) { char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *fdinfo = NULL; diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h index c9d730e25c3..c01f2909527 100644 --- a/src/basic/mountpoint-util.h +++ b/src/basic/mountpoint-util.h @@ -39,6 +39,7 @@ bool is_name_to_handle_at_fatal_error(int err); int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); +int name_to_handle_at_try_fid(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); bool file_handle_equal(const struct file_handle *a, const struct file_handle *b);