Merge pull request #25561 from poettering/btrfs-quota-opath-fix

tmpfiles: fix btrfs quota logic
This commit is contained in:
Yu Watanabe
2022-11-30 09:30:13 +09:00
committed by GitHub
5 changed files with 97 additions and 45 deletions
+31
View File
@@ -780,6 +780,37 @@ int fd_reopen(int fd, int flags) {
return new_fd;
}
int fd_reopen_condition(
int fd,
int flags,
int mask,
int *ret_new_fd) {
int r, new_fd;
assert(fd >= 0);
/* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
* flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
* needed, but only then. */
r = fcntl(fd, F_GETFL);
if (r < 0)
return -errno;
if ((r & mask) == (flags & mask)) {
*ret_new_fd = -1;
return fd;
}
new_fd = fd_reopen(fd, flags);
if (new_fd < 0)
return new_fd;
*ret_new_fd = new_fd;
return new_fd;
}
int read_nr_open(void) {
_cleanup_free_ char *nr_open = NULL;
int r;
+1
View File
@@ -108,6 +108,7 @@ static inline int make_null_stdio(void) {
})
int fd_reopen(int fd, int flags);
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret);
+2 -32
View File
@@ -43,23 +43,7 @@ static int fd_get_devnum(int fd, BlockDeviceLookupFlag flags, dev_t *ret) {
/* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
* handing, to get the backing device node. */
r = fcntl(fd, F_GETFL);
if (r < 0)
return -errno;
if (FLAGS_SET(r, O_PATH)) {
_cleanup_close_ int regfd = -1;
/* The fstat() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot.
* Hence acquire a "real" fd first, without the O_PATH flag. */
regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (regfd < 0)
return regfd;
r = btrfs_get_block_device_fd(regfd, &devnum);
} else
r = btrfs_get_block_device_fd(fd, &devnum);
r = btrfs_get_block_device_fd(fd, &devnum);
if (r == -ENOTTY) /* not btrfs */
return -ENOTBLK;
if (r < 0)
@@ -288,21 +272,7 @@ int get_block_device_fd(int fd, dev_t *ret) {
return 1;
}
r = fcntl(fd, F_GETFL);
if (r < 0)
return -errno;
if (FLAGS_SET(r, O_PATH) && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
_cleanup_close_ int real_fd = -1;
/* The fstat() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot. Hence
* acquire a "real" fd first, without the O_PATH flag. */
real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC);
if (real_fd < 0)
return real_fd;
r = btrfs_get_block_device_fd(real_fd, ret);
} else
r = btrfs_get_block_device_fd(fd, ret);
r = btrfs_get_block_device_fd(fd, ret);
if (r > 0)
return 1;
if (r != -ENOTTY) /* not btrfs */
+16 -13
View File
@@ -107,19 +107,11 @@ int btrfs_subvol_make_fd(int fd, const char *subvolume) {
if (r < 0)
return r;
r = fcntl(fd, F_GETFL);
if (r < 0)
return -errno;
if (FLAGS_SET(r, O_PATH)) {
/* An O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal with
* O_PATH. */
real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (real_fd < 0)
return real_fd;
fd = real_fd;
}
/* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
* with O_PATH. */
fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY, O_PATH|O_DIRECTORY, &real_fd);
if (fd < 0)
return fd;
strncpy(args.name, subvolume, sizeof(args.name)-1);
@@ -255,12 +247,17 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offs
int btrfs_get_block_device_fd(int fd, dev_t *dev) {
struct btrfs_ioctl_fs_info_args fsi = {};
_cleanup_close_ int regfd = -1;
uint64_t id;
int r;
assert(fd >= 0);
assert(dev);
fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, O_PATH, &regfd);
if (fd < 0)
return fd;
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
@@ -1768,6 +1765,7 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
_cleanup_free_ uint64_t *qgroups = NULL;
_cleanup_close_ int real_fd = -1;
uint64_t parent_subvol;
bool changed = false;
int n = 0, r;
@@ -1811,6 +1809,11 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed
* qgroup that then includes all its own child subvolumes.
*/
/* Turn this into a proper fd, if it is currently O_PATH */
fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC, O_PATH, &real_fd);
if (fd < 0)
return fd;
if (subvol_id == 0) {
r = btrfs_is_subvol_fd(fd);
if (r < 0)
+47
View File
@@ -483,6 +483,53 @@ TEST(fd_reopen) {
fd1 = -1;
}
TEST(fd_reopen_condition) {
_cleanup_close_ int fd1 = -1, fd3 = -1;
int fd2, fl;
/* Open without O_PATH */
fd1 = open("/usr/", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
assert_se(fd1 >= 0);
fl = fcntl(fd1, F_GETFL);
assert_se(FLAGS_SET(fl, O_DIRECTORY));
assert_se(!FLAGS_SET(fl, O_PATH));
fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
assert_se(fd2 == fd1);
assert_se(fd3 < 0);
/* Switch on O_PATH */
fd2 = fd_reopen_condition(fd1, O_DIRECTORY|O_PATH, O_DIRECTORY|O_PATH, &fd3);
assert_se(fd2 != fd1);
assert_se(fd3 == fd2);
fl = fcntl(fd2, F_GETFL);
assert_se(FLAGS_SET(fl, O_DIRECTORY));
assert_se(FLAGS_SET(fl, O_PATH));
close_and_replace(fd1, fd3);
fd2 = fd_reopen_condition(fd1, O_DIRECTORY|O_PATH, O_DIRECTORY|O_PATH, &fd3);
assert_se(fd2 == fd1);
assert_se(fd3 < 0);
/* Switch off O_PATH again */
fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
assert_se(fd2 != fd1);
assert_se(fd3 == fd2);
fl = fcntl(fd2, F_GETFL);
assert_se(FLAGS_SET(fl, O_DIRECTORY));
assert_se(!FLAGS_SET(fl, O_PATH));
close_and_replace(fd1, fd3);
fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
assert_se(fd2 == fd1);
assert_se(fd3 < 0);
}
TEST(take_fd) {
_cleanup_close_ int fd1 = -1, fd2 = -1;
int array[2] = { -1, -1 }, i = 0;