test: Modernize btrfs tests
Convert test-btrfs to use the test framework and assertions, merge the physical offset test into it and beef it up to include what TEST-83-BTRFS does and finally get rid of TEST-83-BTRFS as it is unneeded now.
This commit is contained in:
committed by
Daan De Meyer
parent
450853c72c
commit
7cc5d161e6
@@ -256,11 +256,6 @@ executables += [
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-btrfs.c'),
|
||||
'type' : 'manual',
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-btrfs-physical-offset.c'),
|
||||
'type' : 'manual',
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-chase-manual.c'),
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "btrfs-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "log.h"
|
||||
#include "memory-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
uint64_t offset;
|
||||
int r;
|
||||
|
||||
assert(argc == 2);
|
||||
assert(!isempty(argv[1]));
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
fd = open(argv[1], O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
r = btrfs_get_file_physical_offset_fd(fd, &offset);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to get physical offset of '%s': %m", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("%" PRIu64 "\n", offset / page_size());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
+239
-179
@@ -1,202 +1,262 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/magic.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "chattr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "memory-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "pidref.h"
|
||||
#include "process-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "tests.h"
|
||||
#include "time-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
BtrfsQuotaInfo quota;
|
||||
int r, fd;
|
||||
static int open_test_subvol(char **ret_path) {
|
||||
const char *vtd;
|
||||
int r;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
r = var_tmp_dir(&vtd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
_cleanup_free_ char *base = path_join(vtd, "test-btrfs"), *p = NULL;
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
r = tempfn_random(base, /* extra= */ NULL, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
int fd = xopenat_full(AT_FDCWD, p, O_DIRECTORY|O_CREAT|O_CLOEXEC, XO_SUBVOLUME, MODE_INVALID);
|
||||
if (fd < 0)
|
||||
log_error_errno(errno, "Failed to open root directory: %m");
|
||||
return fd;
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(p);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
TEST(info) {
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *dir = NULL;
|
||||
_cleanup_close_ int dir_fd = ASSERT_OK(open_test_subvol(&dir));
|
||||
BtrfsSubvolInfo info;
|
||||
BtrfsQuotaInfo quota;
|
||||
int r;
|
||||
|
||||
ASSERT_OK(btrfs_subvol_get_info_fd(dir_fd, 0, &info));
|
||||
log_info("otime: %s", FORMAT_TIMESTAMP(info.otime));
|
||||
log_info("read-only (search): %s", yes_no(info.read_only));
|
||||
|
||||
r = btrfs_qgroup_get_quota_fd(dir_fd, 0, "a);
|
||||
if (r < 0)
|
||||
log_info_errno(r, "Failed to get quota info: %m");
|
||||
else {
|
||||
BtrfsSubvolInfo info;
|
||||
|
||||
r = btrfs_subvol_get_info_fd(fd, 0, &info);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to get subvolume info: %m");
|
||||
else {
|
||||
log_info("otime: %s", FORMAT_TIMESTAMP(info.otime));
|
||||
log_info("read-only (search): %s", yes_no(info.read_only));
|
||||
}
|
||||
|
||||
r = btrfs_qgroup_get_quota_fd(fd, 0, "a);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to get quota info: %m");
|
||||
else {
|
||||
log_info("referenced: %s", strna(FORMAT_BYTES(quota.referenced)));
|
||||
log_info("exclusive: %s", strna(FORMAT_BYTES(quota.exclusive)));
|
||||
log_info("referenced_max: %s", strna(FORMAT_BYTES(quota.referenced_max)));
|
||||
log_info("exclusive_max: %s", strna(FORMAT_BYTES(quota.exclusive_max)));
|
||||
}
|
||||
|
||||
r = btrfs_subvol_get_read_only_fd(fd);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to get read only flag: %m");
|
||||
else
|
||||
log_info("read-only (ioctl): %s", yes_no(r));
|
||||
|
||||
safe_close(fd);
|
||||
log_info("referenced: %s", strna(FORMAT_BYTES(quota.referenced)));
|
||||
log_info("exclusive: %s", strna(FORMAT_BYTES(quota.exclusive)));
|
||||
log_info("referenced_max: %s", strna(FORMAT_BYTES(quota.referenced_max)));
|
||||
log_info("exclusive_max: %s", strna(FORMAT_BYTES(quota.exclusive_max)));
|
||||
}
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxtest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = write_string_file("/xxxtest/file", "ljsadhfljasdkfhlkjdsfha", WRITE_STRING_FILE_CREATE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to write file: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest2", 0);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make snapshot: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
|
||||
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, 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");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA);
|
||||
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)
|
||||
log_error_errno(r, "Failed to make snapshot: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest2");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3/sub");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
if (mkdir("/xxxrectest/dir", 0755) < 0)
|
||||
log_error_errno(errno, "Failed to make directory: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
if (mkdir("/xxxrectest/dir/xxxrectest4/dir", 0755) < 0)
|
||||
log_error_errno(errno, "Failed to make directory: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
if (mkdir("/xxxrectest/mnt", 0755) < 0)
|
||||
log_error_errno(errno, "Failed to make directory: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxrectest", AT_FDCWD, "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to snapshot subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to recursively remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to recursively remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up auto qgroup: %m");
|
||||
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest/beneath");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up auto qgroup: %m");
|
||||
|
||||
r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up quota limit: %m");
|
||||
|
||||
r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up quota limit: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxquotatest", AT_FDCWD, "/xxxquotatest2",
|
||||
BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up snapshot: %m");
|
||||
|
||||
r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, "a);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to query quota: %m");
|
||||
|
||||
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");
|
||||
|
||||
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)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
return 0;
|
||||
r = ASSERT_OK(btrfs_subvol_get_read_only_fd(dir_fd));
|
||||
log_info("read-only (ioctl): %s", yes_no(r));
|
||||
}
|
||||
|
||||
TEST(subvol) {
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *dir = NULL;
|
||||
_cleanup_close_ int dir_fd = ASSERT_OK(open_test_subvol(&dir));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "test1"));
|
||||
ASSERT_OK(write_string_file_at(dir_fd, "test1/file", "ljsadhfljasdkfhlkjdsfha", WRITE_STRING_FILE_CREATE));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_snapshot_at(dir_fd, "test1", dir_fd, "test2", 0));
|
||||
ASSERT_OK(btrfs_subvol_snapshot_at(dir_fd, "test1", dir_fd, "test3", BTRFS_SNAPSHOT_READ_ONLY));
|
||||
|
||||
_unused_ _cleanup_close_ int locked_fd = ASSERT_OK(btrfs_subvol_snapshot_at(dir_fd, "test1", dir_fd, "test4", BTRFS_SNAPSHOT_LOCK_BSD));
|
||||
ASSERT_ERROR(xopenat_lock(dir_fd, "test4", 0, LOCK_BSD, LOCK_EX|LOCK_NB), EAGAIN);
|
||||
|
||||
/* The destroy ioctl needs CAP_SYS_ADMIN; without it, leave cleanup to rm_rf_subvolume_and_freep. */
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "test1", BTRFS_REMOVE_QUOTA), -EPERM);
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "test2", BTRFS_REMOVE_QUOTA), -EPERM);
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "test3", BTRFS_REMOVE_QUOTA), -EPERM);
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "test4", BTRFS_REMOVE_QUOTA), -EPERM);
|
||||
}
|
||||
|
||||
TEST(fallback_copy) {
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *dir = NULL;
|
||||
_cleanup_close_ int dir_fd = ASSERT_OK(open_test_subvol(&dir));
|
||||
|
||||
/* Snapshot a regular directory (not a subvolume) — exercises the FALLBACK_COPY path. */
|
||||
ASSERT_OK_ERRNO(mkdirat(dir_fd, "src", 0755));
|
||||
ASSERT_OK(write_string_file_at(dir_fd, "src/file1", "hello", WRITE_STRING_FILE_CREATE));
|
||||
ASSERT_OK(write_string_file_at(dir_fd, "src/file2", "world", WRITE_STRING_FILE_CREATE));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_snapshot_at(dir_fd, "src", dir_fd, "snap",
|
||||
BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY));
|
||||
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "snap", BTRFS_REMOVE_QUOTA), -EPERM);
|
||||
}
|
||||
|
||||
TEST(recursive) {
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *dir = NULL;
|
||||
_cleanup_close_ int dir_fd = ASSERT_OK(open_test_subvol(&dir));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "rec"));
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "rec/sv2"));
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "rec/sv3"));
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "rec/sv3/sub"));
|
||||
|
||||
ASSERT_OK_ERRNO(mkdirat(dir_fd, "rec/dir", 0755));
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "rec/dir/sv4"));
|
||||
ASSERT_OK_ERRNO(mkdirat(dir_fd, "rec/dir/sv4/dir", 0755));
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "rec/dir/sv4/dir/sv5"));
|
||||
|
||||
ASSERT_OK_ERRNO(mkdirat(dir_fd, "rec/mnt", 0755));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_snapshot_at(dir_fd, "rec", dir_fd, "rec-snap", BTRFS_SNAPSHOT_RECURSIVE));
|
||||
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "rec", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE), -EPERM);
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "rec-snap", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE), -EPERM);
|
||||
}
|
||||
|
||||
TEST(quota) {
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *dir = NULL;
|
||||
_cleanup_close_ int dir_fd = ASSERT_OK(open_test_subvol(&dir));
|
||||
BtrfsQuotaInfo quota;
|
||||
int r;
|
||||
|
||||
_cleanup_free_ char *qt = ASSERT_NOT_NULL(path_join(dir, "quotatest")),
|
||||
*qt2 = ASSERT_NOT_NULL(path_join(dir, "quotatest2")),
|
||||
*beneath = ASSERT_NOT_NULL(path_join(dir, "quotatest/beneath")),
|
||||
*snap_beneath = ASSERT_NOT_NULL(path_join(dir, "quotatest2/beneath"));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "quotatest"));
|
||||
/* The qgroup/quota ioctls require CAP_SYS_ADMIN; skip the rest of the test if we don't have it
|
||||
* or quotas are not enabled on this filesystem. */
|
||||
r = btrfs_subvol_auto_qgroup(qt, 0, true);
|
||||
if (r == -EPERM)
|
||||
return (void) log_tests_skipped("not running privileged");
|
||||
if (IN_SET(r, -ENOTCONN, -ENOENT))
|
||||
return (void) log_tests_skipped_errno(r, "btrfs quotas not enabled on this filesystem");
|
||||
ASSERT_OK(r);
|
||||
|
||||
ASSERT_OK(btrfs_subvol_make(dir_fd, "quotatest/beneath"));
|
||||
ASSERT_OK(btrfs_subvol_auto_qgroup(beneath, 0, false));
|
||||
ASSERT_OK(btrfs_qgroup_set_limit(beneath, 0, 4ULL * 1024 * 1024 * 1024));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_set_subtree_quota_limit(qt, 0, 5ULL * 1024 * 1024 * 1024));
|
||||
|
||||
ASSERT_OK(btrfs_subvol_snapshot_at(dir_fd, "quotatest", dir_fd, "quotatest2",
|
||||
BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA));
|
||||
|
||||
ASSERT_OK(btrfs_qgroup_get_quota(snap_beneath, 0, "a));
|
||||
ASSERT_EQ(quota.referenced_max, 4ULL * 1024 * 1024 * 1024);
|
||||
|
||||
ASSERT_OK(btrfs_subvol_get_subtree_quota(qt2, 0, "a));
|
||||
ASSERT_EQ(quota.referenced_max, 5ULL * 1024 * 1024 * 1024);
|
||||
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "quotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE), -EPERM);
|
||||
ASSERT_OK_OR(btrfs_subvol_remove_at(dir_fd, "quotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE), -EPERM);
|
||||
}
|
||||
|
||||
TEST(physical_offset) {
|
||||
_cleanup_free_ char *btrfs_progs = NULL;
|
||||
int r = find_executable("btrfs", &btrfs_progs);
|
||||
if (r < 0)
|
||||
return (void) log_tests_skipped_errno(r, "btrfs(8) not found");
|
||||
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *dir = NULL;
|
||||
_cleanup_close_ int dir_fd = ASSERT_OK(open_test_subvol(&dir));
|
||||
|
||||
/* Set NOCOW on the subvol dir so the swapfile inherits it on creation. Older btrfs-progs
|
||||
* versions don't reliably set NOCOW from `btrfs filesystem mkswapfile`. */
|
||||
ASSERT_OK(chattr_fd(dir_fd, FS_NOCOW_FL, FS_NOCOW_FL));
|
||||
|
||||
/* btrfs filesystem mkswapfile produces a NOCOW, contiguous file with a swap header — exactly
|
||||
* what btrfs inspect-internal map-swapfile expects, and what btrfs_get_file_physical_offset_fd
|
||||
* works with. */
|
||||
_cleanup_free_ char *path = ASSERT_NOT_NULL(path_join(dir, "swapfile"));
|
||||
r = ASSERT_OK(pidref_safe_fork("(mkswapfile)",
|
||||
FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_WAIT,
|
||||
NULL));
|
||||
if (r == 0) {
|
||||
execlp(btrfs_progs, "btrfs", "filesystem", "mkswapfile", "-s", "1m", path, NULL);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
_cleanup_close_ int fd = ASSERT_OK_ERRNO(openat(dir_fd, "swapfile", O_RDONLY|O_CLOEXEC|O_NOCTTY));
|
||||
|
||||
unsigned attrs;
|
||||
ASSERT_OK(read_attr_fd(fd, &attrs));
|
||||
if (!FLAGS_SET(attrs, FS_NOCOW_FL) || FLAGS_SET(attrs, FS_COMPR_FL))
|
||||
return (void) log_tests_skipped("swapfile is not NOCOW/non-compressed (old btrfs-progs?)");
|
||||
|
||||
/* btrfs_get_file_physical_offset_fd() uses BTRFS_IOC_TREE_SEARCH, which needs CAP_SYS_ADMIN. */
|
||||
uint64_t offset;
|
||||
r = btrfs_get_file_physical_offset_fd(fd, &offset);
|
||||
if (r == -EPERM)
|
||||
return (void) log_tests_skipped("not running privileged");
|
||||
ASSERT_OK(r);
|
||||
|
||||
/* Cross-check against `btrfs inspect-internal map-swapfile -r`, which prints the first
|
||||
* physical address in page units. */
|
||||
_cleanup_close_pair_ int pipe_fds[2] = EBADF_PAIR;
|
||||
ASSERT_OK_ERRNO(pipe2(pipe_fds, O_CLOEXEC));
|
||||
|
||||
_cleanup_(pidref_done) PidRef inspect = PIDREF_NULL;
|
||||
r = pidref_safe_fork_full("(btrfs-inspect)",
|
||||
(int[3]) { -EBADF, pipe_fds[1], STDERR_FILENO },
|
||||
/* except_fds= */ NULL, /* n_except_fds= */ 0,
|
||||
FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_REARRANGE_STDIO,
|
||||
&inspect);
|
||||
ASSERT_OK(r);
|
||||
if (r == 0) {
|
||||
execlp(btrfs_progs, "btrfs", "inspect-internal", "map-swapfile", "-r", path, NULL);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
pipe_fds[1] = safe_close(pipe_fds[1]);
|
||||
|
||||
_cleanup_fclose_ FILE *f = ASSERT_NOT_NULL(take_fdopen(&pipe_fds[0], "r"));
|
||||
_cleanup_free_ char *out = NULL;
|
||||
ASSERT_OK(read_full_stream(f, &out, /* ret_size= */ NULL));
|
||||
ASSERT_OK_EQ(pidref_wait_for_terminate_and_check("(btrfs-inspect)", &inspect, 0), 0);
|
||||
|
||||
uint64_t expected;
|
||||
ASSERT_OK(safe_atou64(strstrip(out), &expected));
|
||||
ASSERT_EQ(offset / page_size(), expected);
|
||||
log_info("physical offset: page %" PRIu64, expected);
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
const char *vtd;
|
||||
int r;
|
||||
|
||||
r = var_tmp_dir(&vtd);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "Failed to resolve /var/tmp");
|
||||
|
||||
r = path_is_fs_type(vtd, BTRFS_SUPER_MAGIC);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "Failed to determine filesystem type of %s", vtd);
|
||||
if (r == 0)
|
||||
return log_tests_skipped("%s is not on btrfs", vtd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
integration_tests += [
|
||||
integration_test_template + {
|
||||
'name' : fs.name(meson.current_source_dir()),
|
||||
'vm' : true,
|
||||
},
|
||||
]
|
||||
@@ -96,7 +96,6 @@ foreach dirname : [
|
||||
'TEST-80-NOTIFYACCESS',
|
||||
'TEST-81-GENERATORS',
|
||||
'TEST-82-SOFTREBOOT',
|
||||
'TEST-83-BTRFS',
|
||||
'TEST-84-STORAGETM',
|
||||
'TEST-85-NETWORK',
|
||||
'TEST-86-MULTI-PROFILE-UKI',
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
FSTYPE="$(stat --file-system --format "%T" /)"
|
||||
|
||||
if [[ "$FSTYPE" != "btrfs" ]]; then
|
||||
echo "Root filesystem is $FSTYPE instead of btrfs, skipping"
|
||||
exit 77
|
||||
fi
|
||||
|
||||
TEST_BTRFS_OFFSET=/usr/lib/systemd/tests/unit-tests/manual/test-btrfs-physical-offset
|
||||
|
||||
SWAPFILE=/var/tmp/swapfile
|
||||
|
||||
btrfs filesystem mkswapfile -s 10m "$SWAPFILE"
|
||||
sync -f "$SWAPFILE"
|
||||
|
||||
offset_btrfs_progs="$(btrfs inspect-internal map-swapfile -r "$SWAPFILE")"
|
||||
echo "btrfs-progs: $offset_btrfs_progs"
|
||||
|
||||
offset_btrfs_util="$("$TEST_BTRFS_OFFSET" "$SWAPFILE")"
|
||||
echo "btrfs-util: $offset_btrfs_util"
|
||||
|
||||
(( offset_btrfs_progs == offset_btrfs_util ))
|
||||
|
||||
rm -f "$SWAPFILE"
|
||||
|
||||
/usr/lib/systemd/tests/unit-tests/manual/test-btrfs
|
||||
|
||||
touch /testok
|
||||
Reference in New Issue
Block a user