ANDROID: incremental fs: Add ability to run ranges of tests to incfs_test

Also fix test build, test memory leaks

Test: run various range options
Change-Id: I747b3c02f0eb7da440c9d2c2a67e19164b8c9908
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Bug: 264703896
This commit is contained in:
Paul Lawrence
2022-12-20 10:20:12 -08:00
committed by Treehugger Robot
parent 1d9055b834
commit e6c9473f25
2 changed files with 108 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
CFLAGS += -D_FILE_OFFSET_BITS=64 -Wall -Werror -I../.. -I../../../../.. -fno-omit-frame-pointer -fsanitize=address -g CFLAGS += -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wno-deprecated-declarations -I../.. -I../../../../.. -fno-omit-frame-pointer -fsanitize=address -g
LDLIBS := -llz4 -lzstd -lcrypto -lpthread -fsanitize=address LDLIBS := -llz4 -lzstd -lcrypto -lpthread -fsanitize=address
TEST_GEN_PROGS := incfs_test incfs_stress incfs_perf TEST_GEN_PROGS := incfs_test incfs_stress incfs_perf

View File

@@ -60,7 +60,6 @@
struct { struct {
int file; int file;
int test;
bool verbose; bool verbose;
} options; } options;
@@ -935,12 +934,13 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file)
struct incfs_fill_blocks fill_blocks = { struct incfs_fill_blocks fill_blocks = {
.count = file->mtree_block_count, .count = file->mtree_block_count,
}; };
struct incfs_fill_block *fill_block_array = struct incfs_fill_block *fill_block_array;
calloc(fill_blocks.count, sizeof(struct incfs_fill_block));
if (fill_blocks.count == 0) if (fill_blocks.count == 0)
return 0; return 0;
fill_block_array =
calloc(fill_blocks.count, sizeof(struct incfs_fill_block));
if (!fill_block_array) if (!fill_block_array)
return -ENOMEM; return -ENOMEM;
fill_blocks.fill_blocks = ptr_to_u64(fill_block_array); fill_blocks.fill_blocks = ptr_to_u64(fill_block_array);
@@ -1070,6 +1070,7 @@ static int cant_touch_index_test(const char *mount_dir)
free(index_path); free(index_path);
free(dst_name); free(dst_name);
free(filename_in_index); free(filename_in_index);
free(file_path);
if (umount(mount_dir) != 0) { if (umount(mount_dir) != 0) {
print_error("Can't unmout FS"); print_error("Can't unmout FS");
goto failure; goto failure;
@@ -1082,6 +1083,7 @@ failure:
free(dst_name); free(dst_name);
free(index_path); free(index_path);
free(filename_in_index); free(filename_in_index);
free(file_path);
close(cmd_fd); close(cmd_fd);
umount(mount_dir); umount(mount_dir);
return TEST_FAILURE; return TEST_FAILURE;
@@ -1353,9 +1355,13 @@ static int basic_file_ops_test(const char *mount_dir)
goto failure; goto failure;
} }
free(subdir1);
free(subdir2);
return TEST_SUCCESS; return TEST_SUCCESS;
failure: failure:
free(subdir1);
free(subdir2);
close(cmd_fd); close(cmd_fd);
umount(mount_dir); umount(mount_dir);
return TEST_FAILURE; return TEST_FAILURE;
@@ -2637,13 +2643,14 @@ static int emit_partial_test_file_hash(const char *mount_dir,
struct incfs_fill_blocks fill_blocks = { struct incfs_fill_blocks fill_blocks = {
.count = 1, .count = 1,
}; };
struct incfs_fill_block *fill_block_array = struct incfs_fill_block *fill_block_array;
calloc(fill_blocks.count, sizeof(struct incfs_fill_block));
uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
if (file->size <= 4096 / 32 * 4096) if (file->size <= 4096 / 32 * 4096)
return 0; return 0;
fill_block_array =
calloc(fill_blocks.count, sizeof(struct incfs_fill_block));
if (!fill_block_array) if (!fill_block_array)
return -ENOMEM; return -ENOMEM;
fill_blocks.fill_blocks = ptr_to_u64(fill_block_array); fill_blocks.fill_blocks = ptr_to_u64(fill_block_array);
@@ -2678,7 +2685,7 @@ failure:
static int validate_hash_ranges(const char *mount_dir, struct test_file *file) static int validate_hash_ranges(const char *mount_dir, struct test_file *file)
{ {
int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
char *filename = concat_file_name(mount_dir, file->name); char *filename = NULL;
int fd; int fd;
struct incfs_filled_range ranges[128]; struct incfs_filled_range ranges[128];
struct incfs_get_filled_blocks_args fba = { struct incfs_get_filled_blocks_args fba = {
@@ -2694,6 +2701,7 @@ static int validate_hash_ranges(const char *mount_dir, struct test_file *file)
if (file->size <= 4096 / 32 * 4096) if (file->size <= 4096 / 32 * 4096)
return 0; return 0;
filename = concat_file_name(mount_dir, file->name);
fd = open(filename, O_RDONLY | O_CLOEXEC); fd = open(filename, O_RDONLY | O_CLOEXEC);
free(filename); free(filename);
if (fd <= 0) if (fd <= 0)
@@ -2805,12 +2813,8 @@ static int large_file_test(const char *mount_dir)
int result = TEST_FAILURE, ret; int result = TEST_FAILURE, ret;
uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {}; uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {};
int block_count = THREE_GB / INCFS_DATA_FILE_BLOCK_SIZE; int block_count = THREE_GB / INCFS_DATA_FILE_BLOCK_SIZE;
struct incfs_fill_block *block_buf = struct incfs_fill_block *block_buf = NULL;
calloc(block_count, sizeof(struct incfs_fill_block)); struct incfs_fill_blocks fill_blocks;
struct incfs_fill_blocks fill_blocks = {
.count = block_count,
.fill_blocks = ptr_to_u64(block_buf),
};
incfs_uuid_t id; incfs_uuid_t id;
int fd = -1; int fd = -1;
struct statvfs svfs; struct statvfs svfs;
@@ -2846,6 +2850,14 @@ static int large_file_test(const char *mount_dir)
NULL) < 0) NULL) < 0)
goto failure; goto failure;
block_buf = calloc(block_count, sizeof(struct incfs_fill_block));
if (!block_buf)
goto failure;
fill_blocks = (struct incfs_fill_blocks) {
.count = block_count,
.fill_blocks = ptr_to_u64(block_buf),
};
for (i = 0; i < block_count; i++) { for (i = 0; i < block_count; i++) {
block_buf[i].compression = COMPRESSION_NONE; block_buf[i].compression = COMPRESSION_NONE;
block_buf[i].block_index = i; block_buf[i].block_index = i;
@@ -2872,6 +2884,7 @@ failure:
unlink("very_large_file"); unlink("very_large_file");
umount(mount_dir); umount(mount_dir);
free(backing_dir); free(backing_dir);
free(block_buf);
return result; return result;
} }
@@ -3429,7 +3442,7 @@ out:
static int is_close(struct timespec *start, int expected_ms) static int is_close(struct timespec *start, int expected_ms)
{ {
const int allowed_variance = 100; const int allowed_variance = 500;
int result = TEST_FAILURE; int result = TEST_FAILURE;
struct timespec finish; struct timespec finish;
int diff; int diff;
@@ -3438,7 +3451,11 @@ static int is_close(struct timespec *start, int expected_ms)
diff = (finish.tv_sec - start->tv_sec) * 1000 + diff = (finish.tv_sec - start->tv_sec) * 1000 +
(finish.tv_nsec - start->tv_nsec) / 1000000; (finish.tv_nsec - start->tv_nsec) / 1000000;
TESTCOND(diff >= expected_ms - allowed_variance); if(diff < expected_ms - allowed_variance || diff > expected_ms + allowed_variance) {
printf("%d %d %d\n", diff, expected_ms, allowed_variance);
}
TESTCOND(diff >= expected_ms);
TESTCOND(diff <= expected_ms + allowed_variance); TESTCOND(diff <= expected_ms + allowed_variance);
result = TEST_SUCCESS; result = TEST_SUCCESS;
out: out:
@@ -3519,13 +3536,13 @@ static int per_uid_read_timeouts_test(const char *mount_dir)
purt_set[0].max_pending_time_us); purt_set[0].max_pending_time_us);
/* Still 1000 in UID 2 */ /* Still 1000 in UID 2 */
TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
TEST(pid = fork(), pid != -1); TEST(pid = fork(), pid != -1);
if (pid == 0) { if (pid == 0) {
TESTEQUAL(setuid(2), 0); TESTEQUAL(setuid(2), 0);
TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1); TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
exit(0); exit(0);
} }
TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
TESTNE(wait(&status), -1); TESTNE(wait(&status), -1);
TESTEQUAL(WEXITSTATUS(status), 0); TESTEQUAL(WEXITSTATUS(status), 0);
TESTEQUAL(is_close(&start, 1000), 0); TESTEQUAL(is_close(&start, 1000), 0);
@@ -3965,7 +3982,7 @@ static int memzero(const unsigned char *buf, size_t size)
static int validate_verity(const char *mount_dir, struct test_file *file) static int validate_verity(const char *mount_dir, struct test_file *file)
{ {
int result = TEST_FAILURE; int result = TEST_FAILURE;
char *filename = concat_file_name(mount_dir, file->name); char *filename = 0;
int fd = -1; int fd = -1;
uint64_t flags; uint64_t flags;
struct fsverity_digest *digest; struct fsverity_digest *digest;
@@ -4226,6 +4243,8 @@ static int mmap_test(const char *mount_dir)
char *filename = NULL; char *filename = NULL;
int fd = -1; int fd = -1;
char *addr = (void *)-1; char *addr = (void *)-1;
int pid = -1;
int status;
TEST(backing_dir = create_backing_dir(mount_dir), backing_dir); TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0); TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
@@ -4242,23 +4261,26 @@ static int mmap_test(const char *mount_dir)
TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1); TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
TEST(addr = mmap(NULL, file.size, PROT_READ, MAP_PRIVATE, fd, 0), TEST(addr = mmap(NULL, file.size, PROT_READ, MAP_PRIVATE, fd, 0),
addr != (void *) -1); addr != (void *) -1);
TESTEQUAL(mlock(addr, INCFS_DATA_FILE_BLOCK_SIZE), 0); TESTEQUAL(addr[0], 57);
TESTEQUAL(munlock(addr, INCFS_DATA_FILE_BLOCK_SIZE), 0);
TESTEQUAL(mlock(addr + shas_per_block * INCFS_DATA_FILE_BLOCK_SIZE, TEST(pid = fork(), pid != -1);
INCFS_DATA_FILE_BLOCK_SIZE), -1); if (pid == 0) {
TESTEQUAL(mlock(addr + (shas_per_block - 1) * fclose(stderr);
INCFS_DATA_FILE_BLOCK_SIZE, TESTEQUAL(addr[shas_per_block * INCFS_DATA_FILE_BLOCK_SIZE],
INCFS_DATA_FILE_BLOCK_SIZE), 0); -71);
TESTEQUAL(munlock(addr + (shas_per_block - 1) * exit(0);
INCFS_DATA_FILE_BLOCK_SIZE, }
INCFS_DATA_FILE_BLOCK_SIZE), 0); TESTNE(wait(&status), -1);
TESTEQUAL(mlock(addr + (shas_per_block - 1) * TESTEQUAL(status, 256);
INCFS_DATA_FILE_BLOCK_SIZE,
INCFS_DATA_FILE_BLOCK_SIZE * 2), -1); TESTEQUAL(addr[(shas_per_block - 1) * INCFS_DATA_FILE_BLOCK_SIZE], 76);
TESTEQUAL(munmap(addr, file.size), 0); TESTEQUAL(munmap(addr, file.size), 0);
addr = (void *) -1;
result = TEST_SUCCESS; result = TEST_SUCCESS;
out: out:
if (addr != (void *) -1)
munmap(addr, file.size);
free(file.mtree); free(file.mtree);
close(fd); close(fd);
free(filename); free(filename);
@@ -4677,7 +4699,50 @@ static char *setup_mount_dir()
return mount_dir; return mount_dir;
} }
int parse_options(int argc, char *const *argv) static void parse_range(const char *ranges, bool *run_test, size_t tests)
{
size_t i;
char *range;
for (i = 0; i < tests; ++i)
run_test[i] = false;
range = strtok(optarg, ",");
while (range) {
char *dash = strchr(range, '-');
if (dash) {
size_t start = 1, end = tests;
char *end_ptr;
if (dash > range) {
start = strtol(range, &end_ptr, 10);
if (*end_ptr != '-' || start <= 0 || start > tests)
ksft_exit_fail_msg("Bad range\n");
}
if (dash[1]) {
end = strtol(dash + 1, &end_ptr, 10);
if (*end_ptr || end <= start || end > tests)
ksft_exit_fail_msg("Bad range\n");
}
for (i = start; i <= end; ++i)
run_test[i - 1] = true;
} else {
char *end;
long value = strtol(range, &end, 10);
if (*end || value <= 0 || value > tests)
ksft_exit_fail_msg("Bad range\n");
run_test[value - 1] = true;
}
range = strtok(NULL, ",");
}
}
int parse_options(int argc, char *const *argv, bool *run_test,
size_t tests)
{ {
signed char c; signed char c;
@@ -4688,7 +4753,7 @@ int parse_options(int argc, char *const *argv)
break; break;
case 't': case 't':
options.test = strtol(optarg, NULL, 10); parse_range(optarg, run_test, tests);
break; break;
case 'v': case 'v':
@@ -4728,9 +4793,6 @@ int main(int argc, char *argv[])
int i; int i;
int fd, count; int fd, count;
if (parse_options(argc, argv))
ksft_exit_fail_msg("Bad options\n");
// Seed randomness pool for testing on QEMU // Seed randomness pool for testing on QEMU
// NOTE - this abuses the concept of randomness - do *not* ever do this // NOTE - this abuses the concept of randomness - do *not* ever do this
// on a machine for production use - the device will think it has good // on a machine for production use - the device will think it has good
@@ -4784,18 +4846,20 @@ int main(int argc, char *argv[])
MAKE_TEST(stacked_mount_test), MAKE_TEST(stacked_mount_test),
}; };
#undef MAKE_TEST #undef MAKE_TEST
bool run_test[ARRAY_SIZE(cases)];
if (options.test) { for (int i = 0; i < ARRAY_SIZE(cases); ++i)
if (options.test <= 0 || options.test > ARRAY_SIZE(cases)) run_test[i] = true;
ksft_exit_fail_msg("Invalid test\n");
ksft_set_plan(1); if (parse_options(argc, argv, run_test, ARRAY_SIZE(cases)))
run_one_test(mount_dir, &cases[options.test - 1]); ksft_exit_fail_msg("Bad options\n");
} else {
ksft_set_plan(ARRAY_SIZE(cases)); ksft_set_plan(ARRAY_SIZE(cases));
for (i = 0; i < ARRAY_SIZE(cases); ++i) for (i = 0; i < ARRAY_SIZE(run_test); ++i)
if (run_test[i])
run_one_test(mount_dir, &cases[i]); run_one_test(mount_dir, &cases[i]);
} else
ksft_cnt.ksft_xskip++;
umount2(mount_dir, MNT_FORCE); umount2(mount_dir, MNT_FORCE);
rmdir(mount_dir); rmdir(mount_dir);