mirror of
https://github.com/systemd/systemd.git
synced 2026-08-03 22:50:29 +00:00
btrfs-util: Add BTRFS_SNAPSHOT_LOCK_BSD
When making ephemeral snapshots of subvolumes whose cleanup depends on whether they're locked or not, it's necessary to have the lock from the very beginning, so let's support that with a new BTRFS_SNAPSHOT_LOCK_BSD flag.
This commit is contained in:
@@ -1363,9 +1363,26 @@ static int subvol_snapshot_children(
|
||||
if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
|
||||
return -errno;
|
||||
|
||||
if (FLAGS_SET(flags, BTRFS_SNAPSHOT_LOCK_BSD)) {
|
||||
subvolume_fd = xopenat_lock(new_fd, subvolume,
|
||||
O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW,
|
||||
/* xopen_flags = */ 0,
|
||||
/* mode = */ 0,
|
||||
LOCK_BSD,
|
||||
LOCK_EX);
|
||||
if (subvolume_fd < 0)
|
||||
return subvolume_fd;
|
||||
|
||||
r = btrfs_is_subvol_fd(subvolume_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) &&
|
||||
!(flags & BTRFS_SNAPSHOT_QUOTA))
|
||||
return 0;
|
||||
return flags & BTRFS_SNAPSHOT_LOCK_BSD ? TAKE_FD(subvolume_fd) : 0;
|
||||
|
||||
if (old_subvol_id == 0) {
|
||||
r = btrfs_subvol_get_id_fd(old_fd, &old_subvol_id);
|
||||
@@ -1385,7 +1402,7 @@ static int subvol_snapshot_children(
|
||||
if (flags & BTRFS_SNAPSHOT_QUOTA)
|
||||
(void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
|
||||
|
||||
return 0;
|
||||
return flags & BTRFS_SNAPSHOT_LOCK_BSD ? TAKE_FD(subvolume_fd) : 0;
|
||||
}
|
||||
|
||||
args.key.min_offset = args.key.max_offset = old_subvol_id;
|
||||
@@ -1480,7 +1497,8 @@ static int subvol_snapshot_children(
|
||||
return k;
|
||||
}
|
||||
|
||||
r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
|
||||
r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid,
|
||||
flags & ~(BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_LOCK_BSD));
|
||||
|
||||
/* Restore the readonly flag */
|
||||
if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
|
||||
@@ -1503,7 +1521,7 @@ static int subvol_snapshot_children(
|
||||
if (flags & BTRFS_SNAPSHOT_QUOTA)
|
||||
(void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
|
||||
|
||||
return 0;
|
||||
return flags & BTRFS_SNAPSHOT_LOCK_BSD ? TAKE_FD(subvolume_fd) : 0;
|
||||
}
|
||||
|
||||
int btrfs_subvol_snapshot_at_full(
|
||||
@@ -1517,7 +1535,7 @@ int btrfs_subvol_snapshot_at_full(
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_free_ char *subvolume = NULL;
|
||||
_cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF;
|
||||
_cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF, subvolume_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD);
|
||||
@@ -1556,6 +1574,25 @@ int btrfs_subvol_snapshot_at_full(
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(flags, BTRFS_SNAPSHOT_LOCK_BSD)) {
|
||||
subvolume_fd = xopenat_lock(new_fd, subvolume,
|
||||
O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW,
|
||||
/* xopen_flags = */ 0,
|
||||
/* mode = */ 0,
|
||||
LOCK_BSD,
|
||||
LOCK_EX);
|
||||
if (subvolume_fd < 0)
|
||||
return subvolume_fd;
|
||||
|
||||
if (!plain_directory) {
|
||||
r = btrfs_is_subvol_fd(subvolume_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
r = copy_directory_at_full(
|
||||
dir_fdf, from,
|
||||
new_fd, subvolume,
|
||||
@@ -1587,7 +1624,7 @@ int btrfs_subvol_snapshot_at_full(
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return flags & BTRFS_SNAPSHOT_LOCK_BSD ? TAKE_FD(subvolume_fd) : 0;
|
||||
|
||||
fallback_fail:
|
||||
(void) rm_rf_at(new_fd, subvolume, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||
|
||||
@@ -36,6 +36,7 @@ typedef enum BtrfsSnapshotFlags {
|
||||
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 1 << 5, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */
|
||||
BTRFS_SNAPSHOT_SIGINT = 1 << 6, /* Check for SIGINT regularly, and return EINTR if seen */
|
||||
BTRFS_SNAPSHOT_SIGTERM = 1 << 7, /* Ditto, but for SIGTERM */
|
||||
BTRFS_SNAPSHOT_LOCK_BSD = 1 << 8, /* Return a BSD exclusively locked file descriptor referring to snapshot subvolume/directory. */
|
||||
} BtrfsSnapshotFlags;
|
||||
|
||||
typedef enum BtrfsRemoveFlags {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "btrfs-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "log.h"
|
||||
@@ -62,6 +63,14 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make snapshot: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest4", BTRFS_SNAPSHOT_LOCK_BSD);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make snapshot: %m");
|
||||
if (r >= 0)
|
||||
assert_se(xopenat_lock(AT_FDCWD, "/xxxtest4", 0, 0, 0, LOCK_BSD, LOCK_EX|LOCK_NB) == -EAGAIN);
|
||||
|
||||
safe_close(r);
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
@@ -74,6 +83,10 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest4", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/etc", AT_FDCWD, "/etc2",
|
||||
BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
|
||||
if (r < 0)
|
||||
@@ -161,13 +174,15 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to query quota: %m");
|
||||
|
||||
assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024);
|
||||
if (r >= 0)
|
||||
assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024);
|
||||
|
||||
r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, "a);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to query quota: %m");
|
||||
|
||||
assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024);
|
||||
if (r >= 0)
|
||||
assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024);
|
||||
|
||||
r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
|
||||
Reference in New Issue
Block a user