1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-18 10:04:04 +03:00

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.
This commit is contained in:
Lennart Poettering 2024-06-25 12:41:03 +02:00
parent 6fba9a28b9
commit 81995fbb96
3 changed files with 32 additions and 1 deletions

View File

@ -92,3 +92,7 @@
#define RAW_O_LARGEFILE 00100000
#endif
#endif
#ifndef AT_HANDLE_FID
#define AT_HANDLE_FID AT_REMOVEDIR
#endif

View File

@ -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;

View File

@ -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);