hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/tools/testing/selftests/filesystems/incfs/incfs_test.c
....@@ -2,36 +2,117 @@
22 /*
33 * Copyright 2018 Google LLC
44 */
5
+#define _GNU_SOURCE
6
+
57 #include <alloca.h>
68 #include <dirent.h>
79 #include <errno.h>
810 #include <fcntl.h>
911 #include <lz4.h>
12
+#include <poll.h>
1013 #include <stdbool.h>
1114 #include <stdint.h>
1215 #include <stdio.h>
1316 #include <stdlib.h>
1417 #include <string.h>
18
+#include <time.h>
1519 #include <unistd.h>
20
+#include <zstd.h>
1621
22
+#include <sys/inotify.h>
23
+#include <sys/mman.h>
1724 #include <sys/mount.h>
1825 #include <sys/stat.h>
1926 #include <sys/types.h>
2027 #include <sys/wait.h>
2128 #include <sys/xattr.h>
29
+#include <sys/statvfs.h>
2230
2331 #include <linux/random.h>
32
+#include <linux/stat.h>
2433 #include <linux/unistd.h>
2534
35
+#include <openssl/pem.h>
36
+#include <openssl/x509.h>
37
+
2638 #include <kselftest.h>
39
+#include <include/uapi/linux/fsverity.h>
2740
2841 #include "utils.h"
2942
43
+/* Can't include uapi/linux/fs.h because it clashes with mount.h */
44
+#define FS_IOC_GETFLAGS _IOR('f', 1, long)
45
+#define FS_VERITY_FL 0x00100000 /* Verity protected inode */
46
+
47
+#define TEST_SKIP 2
3048 #define TEST_FAILURE 1
3149 #define TEST_SUCCESS 0
32
-#define INCFS_MAX_MTREE_LEVELS 8
3350
3451 #define INCFS_ROOT_INODE 0
52
+
53
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
54
+#define le16_to_cpu(x) (x)
55
+#define le32_to_cpu(x) (x)
56
+#define le64_to_cpu(x) (x)
57
+#else
58
+#error Big endian not supported!
59
+#endif
60
+
61
+struct {
62
+ int file;
63
+ int test;
64
+ bool verbose;
65
+} options;
66
+
67
+#define TESTCOND(condition) \
68
+ do { \
69
+ if (!(condition)) { \
70
+ ksft_print_msg("%s failed %d\n", \
71
+ __func__, __LINE__); \
72
+ goto out; \
73
+ } else if (options.verbose) \
74
+ ksft_print_msg("%s succeeded %d\n", \
75
+ __func__, __LINE__); \
76
+ } while (false)
77
+
78
+#define TEST(statement, condition) \
79
+ do { \
80
+ statement; \
81
+ TESTCOND(condition); \
82
+ } while (false)
83
+
84
+#define TESTEQUAL(statement, res) \
85
+ TESTCOND((statement) == (res))
86
+
87
+#define TESTNE(statement, res) \
88
+ TESTCOND((statement) != (res))
89
+
90
+#define TESTSYSCALL(statement) \
91
+ do { \
92
+ int res = statement; \
93
+ \
94
+ if (res) \
95
+ ksft_print_msg("Failed: %s (%d)\n", \
96
+ strerror(errno), errno); \
97
+ TESTEQUAL(res, 0); \
98
+ } while (false)
99
+
100
+void print_bytes(const void *data, size_t size)
101
+{
102
+ const uint8_t *bytes = data;
103
+ int i;
104
+
105
+ for (i = 0; i < size; ++i) {
106
+ if (i % 0x10 == 0)
107
+ printf("%08x:", i);
108
+ printf("%02x ", (unsigned int) bytes[i]);
109
+ if (i % 0x10 == 0x0f)
110
+ printf("\n");
111
+ }
112
+
113
+ if (i % 0x10 != 0)
114
+ printf("\n");
115
+}
35116
36117 struct hash_block {
37118 char data[INCFS_DATA_FILE_BLOCK_SIZE];
....@@ -54,6 +135,8 @@
54135 struct hash_block *mtree;
55136 int mtree_block_count;
56137 struct test_signature sig;
138
+ unsigned char *verity_sig;
139
+ size_t verity_sig_size;
57140 };
58141
59142 struct test_files_set {
....@@ -103,6 +186,13 @@
103186 .size = 900 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
104187 { .index = 10, .name = "file_big", .size = 500 * 1024 * 1024 }
105188 };
189
+
190
+ if (options.file)
191
+ return (struct test_files_set) {
192
+ .files = files + options.file - 1,
193
+ .files_count = 1,
194
+ };
195
+
106196 return (struct test_files_set){ .files = files,
107197 .files_count = ARRAY_SIZE(files) };
108198 }
....@@ -137,6 +227,17 @@
137227 static loff_t min(loff_t a, loff_t b)
138228 {
139229 return a < b ? a : b;
230
+}
231
+
232
+static int ilog2(size_t n)
233
+{
234
+ int l = 0;
235
+
236
+ while (n > 1) {
237
+ ++l;
238
+ n >>= 1;
239
+ }
240
+ return l;
140241 }
141242
142243 static pid_t flush_and_fork(void)
....@@ -206,6 +307,17 @@
206307 return strdup(path);
207308 }
208309
310
+static char *get_incomplete_filename(const char *mnt_dir, incfs_uuid_t id)
311
+{
312
+ char path[FILENAME_MAX];
313
+ char str_id[1 + 2 * sizeof(id)];
314
+
315
+ bin2hex(str_id, id.bytes, sizeof(id.bytes));
316
+ snprintf(path, ARRAY_SIZE(path), "%s/.incomplete/%s", mnt_dir, str_id);
317
+
318
+ return strdup(path);
319
+}
320
+
209321 int open_file_by_id(const char *mnt_dir, incfs_uuid_t id, bool use_ioctl)
210322 {
211323 char *path = get_index_filename(mnt_dir, id);
....@@ -228,8 +340,7 @@
228340 goto out;
229341 }
230342
231
- if (ioctl(fd, INCFS_IOC_PERMIT_FILL, &permit_fill) != -1 ||
232
- errno != EPERM) {
343
+ if (ioctl(fd, INCFS_IOC_PERMIT_FILL, &permit_fill) != -1) {
233344 print_error(
234345 "Successfully called PERMIT_FILL on non pending_read file");
235346 return -errno;
....@@ -248,7 +359,7 @@
248359 return fd;
249360 }
250361
251
-int get_file_attr(char *mnt_dir, incfs_uuid_t id, char *value, int size)
362
+int get_file_attr(const char *mnt_dir, incfs_uuid_t id, char *value, int size)
252363 {
253364 char *path = get_index_filename(mnt_dir, id);
254365 int res;
....@@ -266,7 +377,13 @@
266377 return !memcmp(id1->bytes, id2->bytes, sizeof(id1->bytes));
267378 }
268379
269
-static int emit_test_blocks(char *mnt_dir, struct test_file *file,
380
+ssize_t ZSTD_compress_default(char *data, char *comp_data, size_t data_size,
381
+ size_t comp_size)
382
+{
383
+ return ZSTD_compress(comp_data, comp_size, data, data_size, 1);
384
+}
385
+
386
+static int emit_test_blocks(const char *mnt_dir, struct test_file *file,
270387 int blocks[], int count)
271388 {
272389 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
....@@ -290,7 +407,8 @@
290407
291408 for (i = 0; i < block_count; i++) {
292409 int block_index = blocks[i];
293
- bool compress = (file->index + block_index) % 2 == 0;
410
+ bool compress_zstd = (file->index + block_index) % 4 == 2;
411
+ bool compress_lz4 = (file->index + block_index) % 4 == 0;
294412 int seed = get_file_block_seed(file->index, block_index);
295413 off_t block_offset =
296414 ((off_t)block_index) * INCFS_DATA_FILE_BLOCK_SIZE;
....@@ -307,10 +425,10 @@
307425 block_size = file->size - block_offset;
308426
309427 rnd_buf(data, block_size, seed);
310
- if (compress) {
311
- size_t comp_size = LZ4_compress_default(
312
- (char *)data, (char *)comp_data, block_size,
313
- ARRAY_SIZE(comp_data));
428
+ if (compress_lz4) {
429
+ size_t comp_size = LZ4_compress_default((char *)data,
430
+ (char *)comp_data, block_size,
431
+ ARRAY_SIZE(comp_data));
314432
315433 if (comp_size <= 0) {
316434 error = -EBADMSG;
....@@ -323,6 +441,22 @@
323441 memcpy(current_data, comp_data, comp_size);
324442 block_size = comp_size;
325443 block_buf[i].compression = COMPRESSION_LZ4;
444
+ } else if (compress_zstd) {
445
+ size_t comp_size = ZSTD_compress(comp_data,
446
+ ARRAY_SIZE(comp_data), data, block_size,
447
+ 1);
448
+
449
+ if (comp_size <= 0) {
450
+ error = -EBADMSG;
451
+ break;
452
+ }
453
+ if (current_data + comp_size > data_end) {
454
+ error = -ENOMEM;
455
+ break;
456
+ }
457
+ memcpy(current_data, comp_data, comp_size);
458
+ block_size = comp_size;
459
+ block_buf[i].compression = COMPRESSION_ZSTD;
326460 } else {
327461 if (current_data + block_size > data_end) {
328462 error = -ENOMEM;
....@@ -376,7 +510,7 @@
376510 return (error < 0) ? error : blocks_written;
377511 }
378512
379
-static int emit_test_block(char *mnt_dir, struct test_file *file,
513
+static int emit_test_block(const char *mnt_dir, struct test_file *file,
380514 int block_index)
381515 {
382516 int res = emit_test_blocks(mnt_dir, file, &block_index, 1);
....@@ -406,7 +540,7 @@
406540 }
407541 }
408542
409
-static int emit_test_file_data(char *mount_dir, struct test_file *file)
543
+static int emit_test_file_data(const char *mount_dir, struct test_file *file)
410544 {
411545 int i;
412546 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
....@@ -439,7 +573,7 @@
439573 return result;
440574 }
441575
442
-static loff_t read_whole_file(char *filename)
576
+static loff_t read_whole_file(const char *filename)
443577 {
444578 int fd = -1;
445579 loff_t result;
....@@ -505,7 +639,7 @@
505639 return result;
506640 }
507641
508
-static char *create_backing_dir(char *mount_dir)
642
+static char *create_backing_dir(const char *mount_dir)
509643 {
510644 struct stat st;
511645 char backing_dir_name[255];
....@@ -541,7 +675,7 @@
541675 return strdup(backing_dir_name);
542676 }
543677
544
-static int validate_test_file_content_with_seed(char *mount_dir,
678
+static int validate_test_file_content_with_seed(const char *mount_dir,
545679 struct test_file *file,
546680 unsigned int shuffle_seed)
547681 {
....@@ -603,12 +737,13 @@
603737 return error;
604738 }
605739
606
-static int validate_test_file_content(char *mount_dir, struct test_file *file)
740
+static int validate_test_file_content(const char *mount_dir,
741
+ struct test_file *file)
607742 {
608743 return validate_test_file_content_with_seed(mount_dir, file, 0);
609744 }
610745
611
-static int data_producer(char *mount_dir, struct test_files_set *test_set)
746
+static int data_producer(const char *mount_dir, struct test_files_set *test_set)
612747 {
613748 int ret = 0;
614749 int timeout_ms = 1000;
....@@ -620,6 +755,55 @@
620755 return -errno;
621756
622757 while ((ret = wait_for_pending_reads(fd, timeout_ms, prs, prs_size)) >
758
+ 0) {
759
+ int read_count = ret;
760
+ int i;
761
+
762
+ for (i = 0; i < read_count; i++) {
763
+ int j = 0;
764
+ struct test_file *file = NULL;
765
+
766
+ for (j = 0; j < test_set->files_count; j++) {
767
+ bool same = same_id(&(test_set->files[j].id),
768
+ &(prs[i].file_id));
769
+
770
+ if (same) {
771
+ file = &test_set->files[j];
772
+ break;
773
+ }
774
+ }
775
+ if (!file) {
776
+ ksft_print_msg(
777
+ "Unknown file in pending reads.\n");
778
+ break;
779
+ }
780
+
781
+ ret = emit_test_block(mount_dir, file,
782
+ prs[i].block_index);
783
+ if (ret < 0) {
784
+ ksft_print_msg("Emitting test data error: %s\n",
785
+ strerror(-ret));
786
+ break;
787
+ }
788
+ }
789
+ }
790
+ close(fd);
791
+ return ret;
792
+}
793
+
794
+static int data_producer2(const char *mount_dir,
795
+ struct test_files_set *test_set)
796
+{
797
+ int ret = 0;
798
+ int timeout_ms = 1000;
799
+ struct incfs_pending_read_info2 prs[100] = {};
800
+ int prs_size = ARRAY_SIZE(prs);
801
+ int fd = open_commands_file(mount_dir);
802
+
803
+ if (fd < 0)
804
+ return -errno;
805
+
806
+ while ((ret = wait_for_pending_reads2(fd, timeout_ms, prs, prs_size)) >
623807 0) {
624808 int read_count = ret;
625809 int i;
....@@ -793,17 +977,15 @@
793977 close(fd);
794978 if (err < fill_blocks.count)
795979 err = errno;
796
- else {
980
+ else
797981 err = 0;
798
- free(file->mtree);
799
- }
800982
801983 failure:
802984 free(fill_block_array);
803985 return err;
804986 }
805987
806
-static int cant_touch_index_test(char *mount_dir)
988
+static int cant_touch_index_test(const char *mount_dir)
807989 {
808990 char *file_name = "test_file";
809991 int file_size = 123;
....@@ -834,6 +1016,12 @@
8341016 err = mkdir(subdir, 0777);
8351017 if (err == 0 || errno != EBUSY) {
8361018 print_error("Shouldn't be able to crate subdir in index\n");
1019
+ goto failure;
1020
+ }
1021
+
1022
+ err = rmdir(index_path);
1023
+ if (err == 0 || errno != EBUSY) {
1024
+ print_error(".index directory should not be removed\n");
8371025 goto failure;
8381026 }
8391027
....@@ -871,6 +1059,12 @@
8711059 goto failure;
8721060 }
8731061
1062
+ err = rename(index_path, dst_name);
1063
+ if (err == 0 || errno != EBUSY) {
1064
+ print_error("Shouldn't rename .index directory\n");
1065
+ goto failure;
1066
+ }
1067
+
8741068 close(cmd_fd);
8751069 free(subdir);
8761070 free(index_path);
....@@ -893,7 +1087,8 @@
8931087 return TEST_FAILURE;
8941088 }
8951089
896
-static bool iterate_directory(char *dir_to_iterate, bool root, int file_count)
1090
+static bool iterate_directory(const char *dir_to_iterate, bool root,
1091
+ int file_count)
8971092 {
8981093 struct expected_name {
8991094 const char *name;
....@@ -902,7 +1097,9 @@
9021097 } names[] = {
9031098 {INCFS_LOG_FILENAME, true, false},
9041099 {INCFS_PENDING_READS_FILENAME, true, false},
1100
+ {INCFS_BLOCKS_WRITTEN_FILENAME, true, false},
9051101 {".index", true, false},
1102
+ {".incomplete", true, false},
9061103 {"..", false, false},
9071104 {".", false, false},
9081105 };
....@@ -998,7 +1195,7 @@
9981195 return pass;
9991196 }
10001197
1001
-static int basic_file_ops_test(char *mount_dir)
1198
+static int basic_file_ops_test(const char *mount_dir)
10021199 {
10031200 struct test_files_set test = get_test_files_set();
10041201 const int file_num = test.files_count;
....@@ -1164,7 +1361,7 @@
11641361 return TEST_FAILURE;
11651362 }
11661363
1167
-static int dynamic_files_and_data_test(char *mount_dir)
1364
+static int dynamic_files_and_data_test(const char *mount_dir)
11681365 {
11691366 struct test_files_set test = get_test_files_set();
11701367 const int file_num = test.files_count;
....@@ -1205,7 +1402,6 @@
12051402 struct test_file *file = &test.files[i];
12061403 int res;
12071404
1208
- build_mtree(file);
12091405 res = emit_file(cmd_fd, NULL, file->name, &file->id,
12101406 file->size, NULL);
12111407 if (res < 0) {
....@@ -1270,7 +1466,7 @@
12701466 return TEST_FAILURE;
12711467 }
12721468
1273
-static int concurrent_reads_and_writes_test(char *mount_dir)
1469
+static int concurrent_reads_and_writes_test(const char *mount_dir)
12741470 {
12751471 struct test_files_set test = get_test_files_set();
12761472 const int file_num = test.files_count;
....@@ -1392,7 +1588,7 @@
13921588 return TEST_FAILURE;
13931589 }
13941590
1395
-static int work_after_remount_test(char *mount_dir)
1591
+static int work_after_remount_test(const char *mount_dir)
13961592 {
13971593 struct test_files_set test = get_test_files_set();
13981594 const int file_num = test.files_count;
....@@ -1418,7 +1614,6 @@
14181614 for (i = 0; i < file_num_stage1; i++) {
14191615 struct test_file *file = &test.files[i];
14201616
1421
- build_mtree(file);
14221617 if (emit_file(cmd_fd, NULL, file->name, &file->id,
14231618 file->size, NULL))
14241619 goto failure;
....@@ -1488,7 +1683,7 @@
14881683 goto failure;
14891684 }
14901685
1491
- if (access(filename_in_index, F_OK) != 0) {
1686
+ if (access(filename_in_index, F_OK) != -1) {
14921687 ksft_print_msg("File %s is still present.\n",
14931688 filename_in_index);
14941689 goto failure;
....@@ -1542,7 +1737,7 @@
15421737 return TEST_FAILURE;
15431738 }
15441739
1545
-static int attribute_test(char *mount_dir)
1740
+static int attribute_test(const char *mount_dir)
15461741 {
15471742 char file_attr[] = "metadata123123";
15481743 char attr_buf[INCFS_MAX_FILE_ATTR_SIZE] = {};
....@@ -1625,7 +1820,7 @@
16251820 return TEST_FAILURE;
16261821 }
16271822
1628
-static int child_procs_waiting_for_data_test(char *mount_dir)
1823
+static int child_procs_waiting_for_data_test(const char *mount_dir)
16291824 {
16301825 struct test_files_set test = get_test_files_set();
16311826 const int file_num = test.files_count;
....@@ -1717,7 +1912,7 @@
17171912 return TEST_FAILURE;
17181913 }
17191914
1720
-static int multiple_providers_test(char *mount_dir)
1915
+static int multiple_providers_test(const char *mount_dir)
17211916 {
17221917 struct test_files_set test = get_test_files_set();
17231918 const int file_num = test.files_count;
....@@ -1733,7 +1928,8 @@
17331928 goto failure;
17341929
17351930 /* Mount FS and release the backing file. (10s wait time) */
1736
- if (mount_fs(mount_dir, backing_dir, 10000) != 0)
1931
+ if (mount_fs_opt(mount_dir, backing_dir,
1932
+ "read_timeout_ms=10000,report_uid", false) != 0)
17371933 goto failure;
17381934
17391935 cmd_fd = open_commands_file(mount_dir);
....@@ -1760,7 +1956,7 @@
17601956 * pending reads.
17611957 */
17621958
1763
- ret = data_producer(mount_dir, &test);
1959
+ ret = data_producer2(mount_dir, &test);
17641960 exit(-ret);
17651961 } else if (producer_pid > 0) {
17661962 producer_pids[i] = producer_pid;
....@@ -1812,8 +2008,47 @@
18122008 return TEST_FAILURE;
18132009 }
18142010
1815
-static int hash_tree_test(char *mount_dir)
2011
+static int validate_hash_tree(const char *mount_dir, struct test_file *file)
18162012 {
2013
+ int result = TEST_FAILURE;
2014
+ char *filename = NULL;
2015
+ int fd = -1;
2016
+ unsigned char *buf;
2017
+ int i, err;
2018
+
2019
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
2020
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
2021
+ TEST(buf = malloc(INCFS_DATA_FILE_BLOCK_SIZE * 8), buf);
2022
+
2023
+ for (i = 0; i < file->mtree_block_count; ) {
2024
+ int blocks_to_read = i % 7 + 1;
2025
+ struct fsverity_read_metadata_arg args = {
2026
+ .metadata_type = FS_VERITY_METADATA_TYPE_MERKLE_TREE,
2027
+ .offset = i * INCFS_DATA_FILE_BLOCK_SIZE,
2028
+ .length = blocks_to_read * INCFS_DATA_FILE_BLOCK_SIZE,
2029
+ .buf_ptr = ptr_to_u64(buf),
2030
+ };
2031
+
2032
+ TEST(err = ioctl(fd, FS_IOC_READ_VERITY_METADATA, &args),
2033
+ err == min(args.length, (file->mtree_block_count - i) *
2034
+ INCFS_DATA_FILE_BLOCK_SIZE));
2035
+ TESTEQUAL(memcmp(buf, file->mtree[i].data, err), 0);
2036
+
2037
+ i += blocks_to_read;
2038
+ }
2039
+
2040
+ result = TEST_SUCCESS;
2041
+
2042
+out:
2043
+ free(buf);
2044
+ close(fd);
2045
+ free(filename);
2046
+ return result;
2047
+}
2048
+
2049
+static int hash_tree_test(const char *mount_dir)
2050
+{
2051
+ int result = TEST_FAILURE;
18172052 char *backing_dir;
18182053 struct test_files_set test = get_test_files_set();
18192054 const int file_num = test.files_count;
....@@ -1878,6 +2113,8 @@
18782113 }
18792114 } else if (validate_test_file_content(mount_dir, file) < 0)
18802115 goto failure;
2116
+ else if (validate_hash_tree(mount_dir, file) < 0)
2117
+ goto failure;
18812118 }
18822119
18832120 /* Unmount and mount again, to that hashes are persistent. */
....@@ -1915,319 +2152,250 @@
19152152 } else if (validate_test_file_content(mount_dir, file) < 0)
19162153 goto failure;
19172154 }
1918
-
1919
- /* Final unmount */
1920
- close(cmd_fd);
1921
- cmd_fd = -1;
1922
- if (umount(mount_dir) != 0) {
1923
- print_error("Can't unmout FS");
1924
- goto failure;
1925
- }
1926
- return TEST_SUCCESS;
2155
+ result = TEST_SUCCESS;
19272156
19282157 failure:
2158
+ for (i = 0; i < file_num; i++) {
2159
+ struct test_file *file = &test.files[i];
2160
+
2161
+ free(file->mtree);
2162
+ }
2163
+
19292164 close(cmd_fd);
19302165 free(backing_dir);
19312166 umount(mount_dir);
1932
- return TEST_FAILURE;
2167
+ return result;
19332168 }
19342169
19352170 enum expected_log { FULL_LOG, NO_LOG, PARTIAL_LOG };
19362171
1937
-static int validate_logs(char *mount_dir, int log_fd, struct test_file *file,
1938
- enum expected_log expected_log)
2172
+static int validate_logs(const char *mount_dir, int log_fd,
2173
+ struct test_file *file,
2174
+ enum expected_log expected_log,
2175
+ bool report_uid, bool expect_data)
19392176 {
2177
+ int result = TEST_FAILURE;
19402178 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
19412179 struct incfs_pending_read_info prs[2048] = {};
2180
+ struct incfs_pending_read_info2 prs2[2048] = {};
2181
+ struct incfs_pending_read_info *previous_record = NULL;
19422182 int prs_size = ARRAY_SIZE(prs);
1943
- int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
1944
- int expected_read_block_cnt;
1945
- int res;
1946
- int read_count;
1947
- int i, j;
1948
- char *filename = concat_file_name(mount_dir, file->name);
1949
- int fd;
2183
+ int block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
2184
+ int expected_read_count, read_count, block_index, read_index;
2185
+ char *filename = NULL;
2186
+ int fd = -1;
19502187
1951
- fd = open(filename, O_RDONLY | O_CLOEXEC);
1952
- free(filename);
1953
- if (fd <= 0)
1954
- return TEST_FAILURE;
2188
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
2189
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
19552190
1956
- if (block_cnt > prs_size)
1957
- block_cnt = prs_size;
1958
- expected_read_block_cnt = block_cnt;
2191
+ if (block_count > prs_size)
2192
+ block_count = prs_size;
2193
+ expected_read_count = block_count;
19592194
1960
- for (i = 0; i < block_cnt; i++) {
1961
- res = pread(fd, data, sizeof(data),
1962
- INCFS_DATA_FILE_BLOCK_SIZE * i);
2195
+ for (block_index = 0; block_index < block_count; block_index++) {
2196
+ int result = pread(fd, data, sizeof(data),
2197
+ INCFS_DATA_FILE_BLOCK_SIZE * block_index);
19632198
19642199 /* Make some read logs of type SAME_FILE_NEXT_BLOCK */
1965
- if (i % 10 == 0)
2200
+ if (block_index % 100 == 10)
19662201 usleep(20000);
19672202
19682203 /* Skip some blocks to make logs of type SAME_FILE */
1969
- if (i % 10 == 5) {
1970
- ++i;
1971
- --expected_read_block_cnt;
2204
+ if (block_index % 10 == 5) {
2205
+ ++block_index;
2206
+ --expected_read_count;
19722207 }
19732208
1974
- if (res <= 0)
1975
- goto failure;
2209
+ if (expect_data)
2210
+ TESTCOND(result > 0);
2211
+
2212
+ if (!expect_data)
2213
+ TESTEQUAL(result, -1);
19762214 }
19772215
1978
- read_count = wait_for_pending_reads(
1979
- log_fd, expected_log == NO_LOG ? 10 : 0, prs, prs_size);
1980
- if (expected_log == NO_LOG) {
1981
- if (read_count == 0)
1982
- goto success;
1983
- if (read_count < 0)
1984
- ksft_print_msg("Error reading logged reads %s.\n",
1985
- strerror(-read_count));
1986
- else
1987
- ksft_print_msg("Somehow read empty logs.\n");
1988
- goto failure;
2216
+ if (report_uid)
2217
+ read_count = wait_for_pending_reads2(log_fd,
2218
+ expected_log == NO_LOG ? 10 : 0,
2219
+ prs2, prs_size);
2220
+ else
2221
+ read_count = wait_for_pending_reads(log_fd,
2222
+ expected_log == NO_LOG ? 10 : 0,
2223
+ prs, prs_size);
2224
+
2225
+ if (expected_log == NO_LOG)
2226
+ TESTEQUAL(read_count, 0);
2227
+
2228
+ if (expected_log == PARTIAL_LOG)
2229
+ TESTCOND(read_count > 0 &&
2230
+ read_count <= expected_read_count);
2231
+
2232
+ if (expected_log == FULL_LOG)
2233
+ TESTEQUAL(read_count, expected_read_count);
2234
+
2235
+ /* If read less than expected, advance block_index appropriately */
2236
+ for (block_index = 0, read_index = 0;
2237
+ read_index < expected_read_count - read_count;
2238
+ block_index++, read_index++)
2239
+ if (block_index % 10 == 5)
2240
+ ++block_index;
2241
+
2242
+ for (read_index = 0; read_index < read_count;
2243
+ block_index++, read_index++) {
2244
+ struct incfs_pending_read_info *record = report_uid ?
2245
+ (struct incfs_pending_read_info *) &prs2[read_index] :
2246
+ &prs[read_index];
2247
+
2248
+ TESTCOND(same_id(&record->file_id, &file->id));
2249
+ TESTEQUAL(record->block_index, block_index);
2250
+ TESTNE(record->timestamp_us, 0);
2251
+ if (previous_record)
2252
+ TESTEQUAL(record->serial_number,
2253
+ previous_record->serial_number + 1);
2254
+
2255
+ previous_record = record;
2256
+ if (block_index % 10 == 5)
2257
+ ++block_index;
19892258 }
19902259
1991
- if (read_count < 0) {
1992
- ksft_print_msg("Error reading logged reads %s.\n",
1993
- strerror(-read_count));
1994
- goto failure;
1995
- }
1996
-
1997
- i = 0;
1998
- if (expected_log == PARTIAL_LOG) {
1999
- if (read_count == 0) {
2000
- ksft_print_msg("No logs %s.\n", file->name);
2001
- goto failure;
2002
- }
2003
-
2004
- for (i = 0, j = 0; j < expected_read_block_cnt - read_count;
2005
- i++, j++)
2006
- if (i % 10 == 5)
2007
- ++i;
2008
-
2009
- } else if (read_count != expected_read_block_cnt) {
2010
- ksft_print_msg("Bad log read count %s %d %d.\n", file->name,
2011
- read_count, expected_read_block_cnt);
2012
- goto failure;
2013
- }
2014
-
2015
- for (j = 0; j < read_count; i++, j++) {
2016
- struct incfs_pending_read_info *read = &prs[j];
2017
-
2018
- if (!same_id(&read->file_id, &file->id)) {
2019
- ksft_print_msg("Bad log read ino %s\n", file->name);
2020
- goto failure;
2021
- }
2022
-
2023
- if (read->block_index != i) {
2024
- ksft_print_msg("Bad log read ino %s %d %d.\n",
2025
- file->name, read->block_index, i);
2026
- goto failure;
2027
- }
2028
-
2029
- if (j != 0) {
2030
- unsigned long psn = prs[j - 1].serial_number;
2031
-
2032
- if (read->serial_number != psn + 1) {
2033
- ksft_print_msg("Bad log read sn %s %d %d.\n",
2034
- file->name, read->serial_number,
2035
- psn);
2036
- goto failure;
2037
- }
2038
- }
2039
-
2040
- if (read->timestamp_us == 0) {
2041
- ksft_print_msg("Bad log read timestamp %s.\n",
2042
- file->name);
2043
- goto failure;
2044
- }
2045
-
2046
- if (i % 10 == 5)
2047
- ++i;
2048
- }
2049
-
2050
-success:
2260
+ result = TEST_SUCCESS;
2261
+out:
20512262 close(fd);
2052
- return TEST_SUCCESS;
2053
-
2054
-failure:
2055
- close(fd);
2056
- return TEST_FAILURE;
2263
+ free(filename);
2264
+ return result;
20572265 }
20582266
2059
-static int read_log_test(char *mount_dir)
2267
+static int read_log_test(const char *mount_dir)
20602268 {
2269
+ int result = TEST_FAILURE;
20612270 struct test_files_set test = get_test_files_set();
20622271 const int file_num = test.files_count;
20632272 int i = 0;
2064
- int cmd_fd = -1, log_fd = -1, drop_caches = -1;
2065
- char *backing_dir;
2273
+ int cmd_fd = -1, log_fd = -1;
2274
+ char *backing_dir = NULL;
20662275
2067
- backing_dir = create_backing_dir(mount_dir);
2068
- if (!backing_dir)
2069
- goto failure;
2070
-
2071
- if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2072
- goto failure;
2073
-
2074
- cmd_fd = open_commands_file(mount_dir);
2075
- if (cmd_fd < 0)
2076
- goto failure;
2077
-
2078
- log_fd = open_log_file(mount_dir);
2079
- if (log_fd < 0)
2080
- ksft_print_msg("Can't open log file.\n");
2081
-
2082
- /* Write data. */
2276
+ /* Create files */
2277
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
2278
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2279
+ "readahead=0,report_uid,read_timeout_ms=0",
2280
+ false), 0);
2281
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
20832282 for (i = 0; i < file_num; i++) {
20842283 struct test_file *file = &test.files[i];
20852284
2086
- if (emit_file(cmd_fd, NULL, file->name, &file->id,
2087
- file->size, NULL))
2088
- goto failure;
2089
-
2090
- if (emit_test_file_data(mount_dir, file))
2091
- goto failure;
2285
+ TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
2286
+ file->size, NULL), 0);
20922287 }
2093
-
2094
- /* Validate data */
2095
- for (i = 0; i < file_num; i++) {
2096
- struct test_file *file = &test.files[i];
2097
-
2098
- if (validate_logs(mount_dir, log_fd, file, FULL_LOG))
2099
- goto failure;
2100
- }
2101
-
2102
- /* Unmount and mount again, to see that logs work after remount. */
21032288 close(cmd_fd);
2104
- close(log_fd);
21052289 cmd_fd = -1;
2106
- if (umount(mount_dir) != 0) {
2107
- print_error("Can't unmout FS");
2108
- goto failure;
2109
- }
21102290
2111
- if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2112
- goto failure;
2291
+ /* Validate logs */
2292
+ TEST(log_fd = open_log_file(mount_dir), log_fd != -1);
2293
+ for (i = 0; i < file_num; i++)
2294
+ TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2295
+ FULL_LOG, true, false), 0);
21132296
2114
- cmd_fd = open_commands_file(mount_dir);
2115
- if (cmd_fd < 0)
2116
- goto failure;
2117
-
2118
- log_fd = open_log_file(mount_dir);
2119
- if (log_fd < 0)
2120
- ksft_print_msg("Can't open log file.\n");
2121
-
2122
- /* Validate data again */
2123
- for (i = 0; i < file_num; i++) {
2124
- struct test_file *file = &test.files[i];
2125
-
2126
- if (validate_logs(mount_dir, log_fd, file, FULL_LOG))
2127
- goto failure;
2128
- }
2129
-
2130
- /*
2131
- * Unmount and mount again with no read log to make sure poll
2132
- * doesn't crash
2133
- */
2134
- close(cmd_fd);
2297
+ /* Unmount and mount again without report_uid */
21352298 close(log_fd);
2136
- if (umount(mount_dir) != 0) {
2137
- print_error("Can't unmout FS");
2138
- goto failure;
2139
- }
2299
+ log_fd = -1;
2300
+ TESTEQUAL(umount(mount_dir), 0);
2301
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2302
+ "readahead=0,read_timeout_ms=0", false), 0);
21402303
2141
- if (mount_fs_opt(mount_dir, backing_dir, "readahead=0,rlog_pages=0",
2142
- false) != 0)
2143
- goto failure;
2304
+ TEST(log_fd = open_log_file(mount_dir), log_fd != -1);
2305
+ for (i = 0; i < file_num; i++)
2306
+ TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2307
+ FULL_LOG, false, false), 0);
21442308
2145
- log_fd = open_log_file(mount_dir);
2146
- if (log_fd < 0)
2147
- ksft_print_msg("Can't open log file.\n");
2309
+ /* No read log to make sure poll doesn't crash */
2310
+ close(log_fd);
2311
+ log_fd = -1;
2312
+ TESTEQUAL(umount(mount_dir), 0);
2313
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2314
+ "readahead=0,rlog_pages=0,read_timeout_ms=0",
2315
+ false), 0);
21482316
2149
- /* Validate data again - note should fail this time */
2317
+ TEST(log_fd = open_log_file(mount_dir), log_fd != -1);
2318
+ for (i = 0; i < file_num; i++)
2319
+ TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2320
+ NO_LOG, false, false), 0);
2321
+
2322
+ /* Remount and check that logs start working again */
2323
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2324
+ "readahead=0,rlog_pages=1,read_timeout_ms=0",
2325
+ true), 0);
2326
+ for (i = 0; i < file_num; i++)
2327
+ TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2328
+ PARTIAL_LOG, false, false), 0);
2329
+
2330
+ /* Remount and check that logs continue working */
2331
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2332
+ "readahead=0,rlog_pages=4,read_timeout_ms=0",
2333
+ true), 0);
2334
+ for (i = 0; i < file_num; i++)
2335
+ TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2336
+ FULL_LOG, false, false), 0);
2337
+
2338
+ /* Check logs work with data */
21502339 for (i = 0; i < file_num; i++) {
2151
- struct test_file *file = &test.files[i];
2152
-
2153
- if (validate_logs(mount_dir, log_fd, file, NO_LOG))
2154
- goto failure;
2155
- }
2156
-
2157
- /*
2158
- * Remount and check that logs start working again
2159
- */
2160
- drop_caches = open("/proc/sys/vm/drop_caches", O_WRONLY | O_CLOEXEC);
2161
- if (drop_caches == -1)
2162
- goto failure;
2163
- i = write(drop_caches, "3", 1);
2164
- close(drop_caches);
2165
- if (i != 1)
2166
- goto failure;
2167
-
2168
- if (mount_fs_opt(mount_dir, backing_dir, "readahead=0,rlog_pages=1",
2169
- true) != 0)
2170
- goto failure;
2171
-
2172
- /* Validate data again */
2173
- for (i = 0; i < file_num; i++) {
2174
- struct test_file *file = &test.files[i];
2175
-
2176
- if (validate_logs(mount_dir, log_fd, file, PARTIAL_LOG))
2177
- goto failure;
2178
- }
2179
-
2180
- /*
2181
- * Remount and check that logs start working again
2182
- */
2183
- drop_caches = open("/proc/sys/vm/drop_caches", O_WRONLY | O_CLOEXEC);
2184
- if (drop_caches == -1)
2185
- goto failure;
2186
- i = write(drop_caches, "3", 1);
2187
- close(drop_caches);
2188
- if (i != 1)
2189
- goto failure;
2190
-
2191
- if (mount_fs_opt(mount_dir, backing_dir, "readahead=0,rlog_pages=4",
2192
- true) != 0)
2193
- goto failure;
2194
-
2195
- /* Validate data again */
2196
- for (i = 0; i < file_num; i++) {
2197
- struct test_file *file = &test.files[i];
2198
-
2199
- if (validate_logs(mount_dir, log_fd, file, FULL_LOG))
2200
- goto failure;
2340
+ TESTEQUAL(emit_test_file_data(mount_dir, &test.files[i]), 0);
2341
+ TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2342
+ FULL_LOG, false, true), 0);
22012343 }
22022344
22032345 /* Final unmount */
22042346 close(log_fd);
2205
- free(backing_dir);
2206
- if (umount(mount_dir) != 0) {
2207
- print_error("Can't unmout FS");
2208
- goto failure;
2209
- }
2347
+ log_fd = -1;
2348
+ TESTEQUAL(umount(mount_dir), 0);
22102349
2211
- return TEST_SUCCESS;
2212
-
2213
-failure:
2350
+ result = TEST_SUCCESS;
2351
+out:
22142352 close(cmd_fd);
22152353 close(log_fd);
22162354 free(backing_dir);
22172355 umount(mount_dir);
2218
- return TEST_FAILURE;
2356
+ return result;
22192357 }
22202358
2221
-static int emit_partial_test_file_data(char *mount_dir, struct test_file *file)
2359
+static int emit_partial_test_file_data(const char *mount_dir,
2360
+ struct test_file *file)
22222361 {
22232362 int i, j;
22242363 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
22252364 int *block_indexes = NULL;
22262365 int result = 0;
22272366 int blocks_written = 0;
2367
+ int bw_fd = -1;
2368
+ char buffer[20];
2369
+ struct pollfd pollfd;
2370
+ long blocks_written_total, blocks_written_new_total;
22282371
22292372 if (file->size == 0)
22302373 return 0;
2374
+
2375
+ bw_fd = open_blocks_written_file(mount_dir);
2376
+ if (bw_fd == -1)
2377
+ return -errno;
2378
+
2379
+ result = read(bw_fd, buffer, sizeof(buffer));
2380
+ if (result <= 0) {
2381
+ result = -EIO;
2382
+ goto out;
2383
+ }
2384
+
2385
+ buffer[result] = 0;
2386
+ blocks_written_total = strtol(buffer, NULL, 10);
2387
+ result = 0;
2388
+
2389
+ pollfd = (struct pollfd) {
2390
+ .fd = bw_fd,
2391
+ .events = POLLIN,
2392
+ };
2393
+
2394
+ result = poll(&pollfd, 1, 0);
2395
+ if (result) {
2396
+ result = -EIO;
2397
+ goto out;
2398
+ }
22312399
22322400 /* Emit 2 blocks, skip 2 blocks etc*/
22332401 block_indexes = calloc(block_cnt, sizeof(*block_indexes));
....@@ -2248,9 +2416,29 @@
22482416 result = -EIO;
22492417 goto out;
22502418 }
2419
+
2420
+ result = poll(&pollfd, 1, 0);
2421
+ if (result != 1 || pollfd.revents != POLLIN) {
2422
+ result = -EIO;
2423
+ goto out;
2424
+ }
2425
+
2426
+ result = read(bw_fd, buffer, sizeof(buffer));
2427
+ buffer[result] = 0;
2428
+ blocks_written_new_total = strtol(buffer, NULL, 10);
2429
+
2430
+ if (blocks_written_new_total - blocks_written_total
2431
+ != blocks_written) {
2432
+ result = -EIO;
2433
+ goto out;
2434
+ }
2435
+
2436
+ blocks_written_total = blocks_written_new_total;
2437
+ result = 0;
22512438 }
22522439 out:
22532440 free(block_indexes);
2441
+ close(bw_fd);
22542442 return result;
22552443 }
22562444
....@@ -2384,7 +2572,7 @@
23842572 return error;
23852573 }
23862574
2387
-static int get_blocks_test(char *mount_dir)
2575
+static int get_blocks_test(const char *mount_dir)
23882576 {
23892577 char *backing_dir;
23902578 int cmd_fd = -1;
....@@ -2441,7 +2629,8 @@
24412629 return TEST_FAILURE;
24422630 }
24432631
2444
-static int emit_partial_test_file_hash(char *mount_dir, struct test_file *file)
2632
+static int emit_partial_test_file_hash(const char *mount_dir,
2633
+ struct test_file *file)
24452634 {
24462635 int err;
24472636 int fd;
....@@ -2453,9 +2642,6 @@
24532642 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
24542643
24552644 if (file->size <= 4096 / 32 * 4096)
2456
- return 0;
2457
-
2458
- if (fill_blocks.count == 0)
24592645 return 0;
24602646
24612647 if (!fill_block_array)
....@@ -2559,7 +2745,7 @@
25592745 return error;
25602746 }
25612747
2562
-static int get_hash_blocks_test(char *mount_dir)
2748
+static int get_hash_blocks_test(const char *mount_dir)
25632749 {
25642750 char *backing_dir;
25652751 int cmd_fd = -1;
....@@ -2609,14 +2795,16 @@
26092795 return TEST_FAILURE;
26102796 }
26112797
2612
-static int large_file(char *mount_dir)
2798
+#define THREE_GB (3LL * 1024 * 1024 * 1024)
2799
+#define FOUR_GB (4LL * 1024 * 1024 * 1024) /* Have 1GB of margin */
2800
+static int large_file_test(const char *mount_dir)
26132801 {
26142802 char *backing_dir;
26152803 int cmd_fd = -1;
26162804 int i;
2617
- int result = TEST_FAILURE;
2805
+ int result = TEST_FAILURE, ret;
26182806 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {};
2619
- int block_count = 3LL * 1024 * 1024 * 1024 / INCFS_DATA_FILE_BLOCK_SIZE;
2807
+ int block_count = THREE_GB / INCFS_DATA_FILE_BLOCK_SIZE;
26202808 struct incfs_fill_block *block_buf =
26212809 calloc(block_count, sizeof(struct incfs_fill_block));
26222810 struct incfs_fill_blocks fill_blocks = {
....@@ -2624,7 +2812,23 @@
26242812 .fill_blocks = ptr_to_u64(block_buf),
26252813 };
26262814 incfs_uuid_t id;
2627
- int fd;
2815
+ int fd = -1;
2816
+ struct statvfs svfs;
2817
+ unsigned long long free_disksz;
2818
+
2819
+ ret = statvfs(mount_dir, &svfs);
2820
+ if (ret) {
2821
+ ksft_print_msg("Can't get disk size. Skipping %s...\n", __func__);
2822
+ return TEST_SKIP;
2823
+ }
2824
+
2825
+ free_disksz = (unsigned long long)svfs.f_bavail * svfs.f_bsize;
2826
+
2827
+ if (FOUR_GB > free_disksz) {
2828
+ ksft_print_msg("Not enough free disk space (%lldMB). Skipping %s...\n",
2829
+ free_disksz >> 20, __func__);
2830
+ return TEST_SKIP;
2831
+ }
26282832
26292833 backing_dir = create_backing_dir(mount_dir);
26302834 if (!backing_dir)
....@@ -2665,6 +2869,1765 @@
26652869 failure:
26662870 close(fd);
26672871 close(cmd_fd);
2872
+ unlink("very_large_file");
2873
+ umount(mount_dir);
2874
+ free(backing_dir);
2875
+ return result;
2876
+}
2877
+
2878
+static int validate_mapped_file(const char *orig_name, const char *name,
2879
+ size_t size, size_t offset)
2880
+{
2881
+ struct stat st;
2882
+ int orig_fd = -1, fd = -1;
2883
+ size_t block;
2884
+ int result = TEST_FAILURE;
2885
+
2886
+ if (stat(name, &st)) {
2887
+ ksft_print_msg("Failed to stat %s with error %s\n",
2888
+ name, strerror(errno));
2889
+ goto failure;
2890
+ }
2891
+
2892
+ if (size != st.st_size) {
2893
+ ksft_print_msg("Mismatched file sizes for file %s - expected %llu, got %llu\n",
2894
+ name, size, st.st_size);
2895
+ goto failure;
2896
+ }
2897
+
2898
+ fd = open(name, O_RDONLY | O_CLOEXEC);
2899
+ if (fd == -1) {
2900
+ ksft_print_msg("Failed to open %s with error %s\n", name,
2901
+ strerror(errno));
2902
+ goto failure;
2903
+ }
2904
+
2905
+ orig_fd = open(orig_name, O_RDONLY | O_CLOEXEC);
2906
+ if (orig_fd == -1) {
2907
+ ksft_print_msg("Failed to open %s with error %s\n", orig_name,
2908
+ strerror(errno));
2909
+ goto failure;
2910
+ }
2911
+
2912
+ for (block = 0; block < size; block += INCFS_DATA_FILE_BLOCK_SIZE) {
2913
+ uint8_t orig_data[INCFS_DATA_FILE_BLOCK_SIZE];
2914
+ uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2915
+ ssize_t orig_read, mapped_read;
2916
+
2917
+ orig_read = pread(orig_fd, orig_data,
2918
+ INCFS_DATA_FILE_BLOCK_SIZE, block + offset);
2919
+ mapped_read = pread(fd, data, INCFS_DATA_FILE_BLOCK_SIZE,
2920
+ block);
2921
+
2922
+ if (orig_read < mapped_read ||
2923
+ mapped_read != min(size - block,
2924
+ INCFS_DATA_FILE_BLOCK_SIZE)) {
2925
+ ksft_print_msg("Failed to read enough data: %llu %llu %llu %lld %lld\n",
2926
+ block, size, offset, orig_read,
2927
+ mapped_read);
2928
+ goto failure;
2929
+ }
2930
+
2931
+ if (memcmp(orig_data, data, mapped_read)) {
2932
+ ksft_print_msg("Data doesn't match: %llu %llu %llu %lld %lld\n",
2933
+ block, size, offset, orig_read,
2934
+ mapped_read);
2935
+ goto failure;
2936
+ }
2937
+ }
2938
+
2939
+ result = TEST_SUCCESS;
2940
+
2941
+failure:
2942
+ close(orig_fd);
2943
+ close(fd);
2944
+ return result;
2945
+}
2946
+
2947
+static int mapped_file_test(const char *mount_dir)
2948
+{
2949
+ char *backing_dir;
2950
+ int result = TEST_FAILURE;
2951
+ int cmd_fd = -1;
2952
+ int i;
2953
+ struct test_files_set test = get_test_files_set();
2954
+ const int file_num = test.files_count;
2955
+
2956
+ backing_dir = create_backing_dir(mount_dir);
2957
+ if (!backing_dir)
2958
+ goto failure;
2959
+
2960
+ if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2961
+ goto failure;
2962
+
2963
+ cmd_fd = open_commands_file(mount_dir);
2964
+ if (cmd_fd < 0)
2965
+ goto failure;
2966
+
2967
+ for (i = 0; i < file_num; ++i) {
2968
+ struct test_file *file = &test.files[i];
2969
+ size_t blocks = file->size / INCFS_DATA_FILE_BLOCK_SIZE;
2970
+ size_t mapped_offset = blocks / 4 *
2971
+ INCFS_DATA_FILE_BLOCK_SIZE;
2972
+ size_t mapped_size = file->size / 4 * 3 - mapped_offset;
2973
+ struct incfs_create_mapped_file_args mfa;
2974
+ char mapped_file_name[FILENAME_MAX];
2975
+ char orig_file_path[PATH_MAX];
2976
+ char mapped_file_path[PATH_MAX];
2977
+
2978
+ if (emit_file(cmd_fd, NULL, file->name, &file->id, file->size,
2979
+ NULL) < 0)
2980
+ goto failure;
2981
+
2982
+ if (emit_test_file_data(mount_dir, file))
2983
+ goto failure;
2984
+
2985
+ if (snprintf(mapped_file_name, ARRAY_SIZE(mapped_file_name),
2986
+ "%s.mapped", file->name) < 0)
2987
+ goto failure;
2988
+
2989
+ mfa = (struct incfs_create_mapped_file_args) {
2990
+ .size = mapped_size,
2991
+ .mode = 0664,
2992
+ .file_name = ptr_to_u64(mapped_file_name),
2993
+ .source_file_id = file->id,
2994
+ .source_offset = mapped_offset,
2995
+ };
2996
+
2997
+ result = ioctl(cmd_fd, INCFS_IOC_CREATE_MAPPED_FILE, &mfa);
2998
+ if (result) {
2999
+ ksft_print_msg(
3000
+ "Failed to create mapped file with error %d\n",
3001
+ result);
3002
+ goto failure;
3003
+ }
3004
+
3005
+ result = snprintf(orig_file_path,
3006
+ ARRAY_SIZE(orig_file_path), "%s/%s",
3007
+ mount_dir, file->name);
3008
+
3009
+ if (result < 0 || result >= ARRAY_SIZE(mapped_file_path)) {
3010
+ result = TEST_FAILURE;
3011
+ goto failure;
3012
+ }
3013
+
3014
+ result = snprintf(mapped_file_path,
3015
+ ARRAY_SIZE(mapped_file_path), "%s/%s",
3016
+ mount_dir, mapped_file_name);
3017
+
3018
+ if (result < 0 || result >= ARRAY_SIZE(mapped_file_path)) {
3019
+ result = TEST_FAILURE;
3020
+ goto failure;
3021
+ }
3022
+
3023
+ result = validate_mapped_file(orig_file_path, mapped_file_path,
3024
+ mapped_size, mapped_offset);
3025
+ if (result)
3026
+ goto failure;
3027
+ }
3028
+
3029
+failure:
3030
+ close(cmd_fd);
3031
+ umount(mount_dir);
3032
+ free(backing_dir);
3033
+ return result;
3034
+}
3035
+
3036
+static const char v1_file[] = {
3037
+ /* Header */
3038
+ /* 0x00: Magic number */
3039
+ 0x49, 0x4e, 0x43, 0x46, 0x53, 0x00, 0x00, 0x00,
3040
+ /* 0x08: Version */
3041
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3042
+ /* 0x10: Header size */
3043
+ 0x38, 0x00,
3044
+ /* 0x12: Block size */
3045
+ 0x00, 0x10,
3046
+ /* 0x14: Flags */
3047
+ 0x00, 0x00, 0x00, 0x00,
3048
+ /* 0x18: First md offset */
3049
+ 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3050
+ /* 0x20: File size */
3051
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3052
+ /* 0x28: UUID */
3053
+ 0x8c, 0x7d, 0xd9, 0x22, 0xad, 0x47, 0x49, 0x4f,
3054
+ 0xc0, 0x2c, 0x38, 0x8e, 0x12, 0xc0, 0x0e, 0xac,
3055
+
3056
+ /* 0x38: Attribute */
3057
+ 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
3058
+ 0x31, 0x32, 0x33, 0x31, 0x32, 0x33,
3059
+
3060
+ /* Attribute md record */
3061
+ /* 0x46: Type */
3062
+ 0x02,
3063
+ /* 0x47: Size */
3064
+ 0x25, 0x00,
3065
+ /* 0x49: CRC */
3066
+ 0x9a, 0xef, 0xef, 0x72,
3067
+ /* 0x4d: Next md offset */
3068
+ 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3069
+ /* 0x55: Prev md offset */
3070
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3071
+ /* 0x5d: fa_offset */
3072
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3073
+ /* 0x65: fa_size */
3074
+ 0x0e, 0x00,
3075
+ /* 0x67: fa_crc */
3076
+ 0xfb, 0x5e, 0x72, 0x89,
3077
+
3078
+ /* Blockmap table */
3079
+ /* 0x6b: First 10-byte entry */
3080
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3081
+
3082
+ /* Blockmap md record */
3083
+ /* 0x75: Type */
3084
+ 0x01,
3085
+ /* 0x76: Size */
3086
+ 0x23, 0x00,
3087
+ /* 0x78: CRC */
3088
+ 0x74, 0x45, 0xd3, 0xb9,
3089
+ /* 0x7c: Next md offset */
3090
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3091
+ /* 0x84: Prev md offset */
3092
+ 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3093
+ /* 0x8c: blockmap offset */
3094
+ 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3095
+ /* 0x94: blockmap count */
3096
+ 0x01, 0x00, 0x00, 0x00,
3097
+};
3098
+
3099
+static int compatibility_test(const char *mount_dir)
3100
+{
3101
+ static const char *name = "file";
3102
+ int result = TEST_FAILURE;
3103
+ char *backing_dir = NULL;
3104
+ char *filename = NULL;
3105
+ int fd = -1;
3106
+ uint64_t size = 0x0c;
3107
+
3108
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3109
+ TEST(filename = concat_file_name(backing_dir, name), filename);
3110
+ TEST(fd = open(filename, O_CREAT | O_WRONLY | O_CLOEXEC, 0777),
3111
+ fd != -1);
3112
+ TESTEQUAL(write(fd, v1_file, sizeof(v1_file)), sizeof(v1_file));
3113
+ TESTEQUAL(fsetxattr(fd, INCFS_XATTR_SIZE_NAME, &size, sizeof(size), 0),
3114
+ 0);
3115
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 50), 0);
3116
+ free(filename);
3117
+ TEST(filename = concat_file_name(mount_dir, name), filename);
3118
+ close(fd);
3119
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3120
+
3121
+ result = TEST_SUCCESS;
3122
+out:
3123
+ close(fd);
3124
+ umount(mount_dir);
3125
+ free(backing_dir);
3126
+ free(filename);
3127
+ return result;
3128
+}
3129
+
3130
+static int zero_blocks_written_count(int fd, uint32_t data_blocks_written,
3131
+ uint32_t hash_blocks_written)
3132
+{
3133
+ int test_result = TEST_FAILURE;
3134
+ uint64_t offset;
3135
+ uint8_t type;
3136
+ uint32_t bw;
3137
+
3138
+ /* Get first md record */
3139
+ TESTEQUAL(pread(fd, &offset, sizeof(offset), 24), sizeof(offset));
3140
+
3141
+ /* Find status md record */
3142
+ for (;;) {
3143
+ TESTNE(offset, 0);
3144
+ TESTEQUAL(pread(fd, &type, sizeof(type), le64_to_cpu(offset)),
3145
+ sizeof(type));
3146
+ if (type == 4)
3147
+ break;
3148
+ TESTEQUAL(pread(fd, &offset, sizeof(offset),
3149
+ le64_to_cpu(offset) + 7),
3150
+ sizeof(offset));
3151
+ }
3152
+
3153
+ /* Read blocks_written */
3154
+ offset = le64_to_cpu(offset);
3155
+ TESTEQUAL(pread(fd, &bw, sizeof(bw), offset + 23), sizeof(bw));
3156
+ TESTEQUAL(le32_to_cpu(bw), data_blocks_written);
3157
+ TESTEQUAL(pread(fd, &bw, sizeof(bw), offset + 27), sizeof(bw));
3158
+ TESTEQUAL(le32_to_cpu(bw), hash_blocks_written);
3159
+
3160
+ /* Write out zero */
3161
+ bw = 0;
3162
+ TESTEQUAL(pwrite(fd, &bw, sizeof(bw), offset + 23), sizeof(bw));
3163
+ TESTEQUAL(pwrite(fd, &bw, sizeof(bw), offset + 27), sizeof(bw));
3164
+
3165
+ test_result = TEST_SUCCESS;
3166
+out:
3167
+ return test_result;
3168
+}
3169
+
3170
+static int validate_block_count(const char *mount_dir, const char *backing_dir,
3171
+ struct test_file *file,
3172
+ int total_data_blocks, int filled_data_blocks,
3173
+ int total_hash_blocks, int filled_hash_blocks)
3174
+{
3175
+ char *filename = NULL;
3176
+ char *backing_filename = NULL;
3177
+ int fd = -1;
3178
+ struct incfs_get_block_count_args bca = {};
3179
+ int test_result = TEST_FAILURE;
3180
+ struct incfs_filled_range ranges[128];
3181
+ struct incfs_get_filled_blocks_args fba = {
3182
+ .range_buffer = ptr_to_u64(ranges),
3183
+ .range_buffer_size = sizeof(ranges),
3184
+ };
3185
+ int cmd_fd = -1;
3186
+ struct incfs_permit_fill permit_fill;
3187
+
3188
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
3189
+ TEST(backing_filename = concat_file_name(backing_dir, file->name),
3190
+ backing_filename);
3191
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3192
+
3193
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3194
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3195
+ TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks);
3196
+ TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3197
+ TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks);
3198
+
3199
+ close(fd);
3200
+ TESTEQUAL(umount(mount_dir), 0);
3201
+ TEST(fd = open(backing_filename, O_RDWR | O_CLOEXEC), fd != -1);
3202
+ TESTEQUAL(zero_blocks_written_count(fd, filled_data_blocks,
3203
+ filled_hash_blocks),
3204
+ TEST_SUCCESS);
3205
+ close(fd);
3206
+ fd = -1;
3207
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
3208
+ 0);
3209
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3210
+
3211
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3212
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3213
+ TESTEQUAL(bca.filled_data_blocks_out, 0);
3214
+ TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3215
+ TESTEQUAL(bca.filled_hash_blocks_out, 0);
3216
+
3217
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3218
+ permit_fill.file_descriptor = fd;
3219
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill), 0);
3220
+ do {
3221
+ ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
3222
+ fba.start_index = fba.index_out + 1;
3223
+ } while (fba.index_out < fba.total_blocks_out);
3224
+
3225
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3226
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3227
+ TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks);
3228
+ TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3229
+ TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks);
3230
+
3231
+ test_result = TEST_SUCCESS;
3232
+out:
3233
+ close(cmd_fd);
3234
+ close(fd);
3235
+ free(filename);
3236
+ free(backing_filename);
3237
+ return test_result;
3238
+}
3239
+
3240
+
3241
+
3242
+static int validate_data_block_count(const char *mount_dir,
3243
+ const char *backing_dir,
3244
+ struct test_file *file)
3245
+{
3246
+ const int total_data_blocks = 1 + (file->size - 1) /
3247
+ INCFS_DATA_FILE_BLOCK_SIZE;
3248
+ const int filled_data_blocks = (total_data_blocks + 1) / 2;
3249
+
3250
+ int test_result = TEST_FAILURE;
3251
+ char *filename = NULL;
3252
+ char *incomplete_filename = NULL;
3253
+ struct stat stat_buf_incomplete, stat_buf_file;
3254
+ int fd = -1;
3255
+ struct incfs_get_block_count_args bca = {};
3256
+ int i;
3257
+
3258
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
3259
+ TEST(incomplete_filename = get_incomplete_filename(mount_dir, file->id),
3260
+ incomplete_filename);
3261
+
3262
+ TESTEQUAL(stat(filename, &stat_buf_file), 0);
3263
+ TESTEQUAL(stat(incomplete_filename, &stat_buf_incomplete), 0);
3264
+ TESTEQUAL(stat_buf_file.st_ino, stat_buf_incomplete.st_ino);
3265
+ TESTEQUAL(stat_buf_file.st_nlink, 3);
3266
+
3267
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3268
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3269
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3270
+ TESTEQUAL(bca.filled_data_blocks_out, 0);
3271
+ TESTEQUAL(bca.total_hash_blocks_out, 0);
3272
+ TESTEQUAL(bca.filled_hash_blocks_out, 0);
3273
+
3274
+ for (i = 0; i < total_data_blocks; i += 2)
3275
+ TESTEQUAL(emit_test_block(mount_dir, file, i), 0);
3276
+
3277
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3278
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3279
+ TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks);
3280
+ TESTEQUAL(bca.total_hash_blocks_out, 0);
3281
+ TESTEQUAL(bca.filled_hash_blocks_out, 0);
3282
+ close(fd);
3283
+ fd = -1;
3284
+
3285
+ TESTEQUAL(validate_block_count(mount_dir, backing_dir, file,
3286
+ total_data_blocks, filled_data_blocks,
3287
+ 0, 0),
3288
+ 0);
3289
+
3290
+ for (i = 1; i < total_data_blocks; i += 2)
3291
+ TESTEQUAL(emit_test_block(mount_dir, file, i), 0);
3292
+
3293
+ TESTEQUAL(stat(incomplete_filename, &stat_buf_incomplete), -1);
3294
+ TESTEQUAL(errno, ENOENT);
3295
+
3296
+ test_result = TEST_SUCCESS;
3297
+out:
3298
+ close(fd);
3299
+ free(incomplete_filename);
3300
+ free(filename);
3301
+ return test_result;
3302
+}
3303
+
3304
+static int data_block_count_test(const char *mount_dir)
3305
+{
3306
+ int result = TEST_FAILURE;
3307
+ char *backing_dir;
3308
+ int cmd_fd = -1;
3309
+ int i;
3310
+ struct test_files_set test = get_test_files_set();
3311
+
3312
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3313
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
3314
+ 0);
3315
+
3316
+ for (i = 0; i < test.files_count; ++i) {
3317
+ struct test_file *file = &test.files[i];
3318
+
3319
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3320
+ TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
3321
+ file->size, NULL),
3322
+ 0);
3323
+ close(cmd_fd);
3324
+ cmd_fd = -1;
3325
+
3326
+ TESTEQUAL(validate_data_block_count(mount_dir, backing_dir,
3327
+ file),
3328
+ 0);
3329
+ }
3330
+
3331
+ result = TEST_SUCCESS;
3332
+out:
3333
+ close(cmd_fd);
3334
+ umount(mount_dir);
3335
+ free(backing_dir);
3336
+ return result;
3337
+}
3338
+
3339
+static int validate_hash_block_count(const char *mount_dir,
3340
+ const char *backing_dir,
3341
+ struct test_file *file)
3342
+{
3343
+ const int digest_size = SHA256_DIGEST_SIZE;
3344
+ const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
3345
+ const int total_data_blocks = 1 + (file->size - 1) /
3346
+ INCFS_DATA_FILE_BLOCK_SIZE;
3347
+
3348
+ int result = TEST_FAILURE;
3349
+ int hash_layer = total_data_blocks;
3350
+ int total_hash_blocks = 0;
3351
+ int filled_hash_blocks;
3352
+ char *filename = NULL;
3353
+ int fd = -1;
3354
+ struct incfs_get_block_count_args bca = {};
3355
+
3356
+ while (hash_layer > 1) {
3357
+ hash_layer = (hash_layer + hash_per_block - 1) / hash_per_block;
3358
+ total_hash_blocks += hash_layer;
3359
+ }
3360
+ filled_hash_blocks = total_hash_blocks > 1 ? 1 : 0;
3361
+
3362
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
3363
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3364
+
3365
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3366
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3367
+ TESTEQUAL(bca.filled_data_blocks_out, 0);
3368
+ TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3369
+ TESTEQUAL(bca.filled_hash_blocks_out, 0);
3370
+
3371
+ TESTEQUAL(emit_partial_test_file_hash(mount_dir, file), 0);
3372
+
3373
+ TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3374
+ TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3375
+ TESTEQUAL(bca.filled_data_blocks_out, 0);
3376
+ TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3377
+ TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks);
3378
+ close(fd);
3379
+ fd = -1;
3380
+
3381
+ if (filled_hash_blocks)
3382
+ TESTEQUAL(validate_block_count(mount_dir, backing_dir, file,
3383
+ total_data_blocks, 0,
3384
+ total_hash_blocks, filled_hash_blocks),
3385
+ 0);
3386
+
3387
+ result = TEST_SUCCESS;
3388
+out:
3389
+ close(fd);
3390
+ free(filename);
3391
+ return result;
3392
+}
3393
+
3394
+static int hash_block_count_test(const char *mount_dir)
3395
+{
3396
+ int result = TEST_FAILURE;
3397
+ char *backing_dir;
3398
+ int cmd_fd = -1;
3399
+ int i;
3400
+ struct test_files_set test = get_test_files_set();
3401
+
3402
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3403
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
3404
+ 0);
3405
+
3406
+ for (i = 0; i < test.files_count; i++) {
3407
+ struct test_file *file = &test.files[i];
3408
+
3409
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3410
+ TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
3411
+ file->size, file->root_hash,
3412
+ file->sig.add_data),
3413
+ 0);
3414
+ close(cmd_fd);
3415
+ cmd_fd = -1;
3416
+
3417
+ TESTEQUAL(validate_hash_block_count(mount_dir, backing_dir,
3418
+ &test.files[i]),
3419
+ 0);
3420
+ }
3421
+
3422
+ result = TEST_SUCCESS;
3423
+out:
3424
+ close(cmd_fd);
3425
+ umount(mount_dir);
3426
+ free(backing_dir);
3427
+ return result;
3428
+}
3429
+
3430
+static int is_close(struct timespec *start, int expected_ms)
3431
+{
3432
+ const int allowed_variance = 100;
3433
+ int result = TEST_FAILURE;
3434
+ struct timespec finish;
3435
+ int diff;
3436
+
3437
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &finish), 0);
3438
+ diff = (finish.tv_sec - start->tv_sec) * 1000 +
3439
+ (finish.tv_nsec - start->tv_nsec) / 1000000;
3440
+
3441
+ TESTCOND(diff >= expected_ms - allowed_variance);
3442
+ TESTCOND(diff <= expected_ms + allowed_variance);
3443
+ result = TEST_SUCCESS;
3444
+out:
3445
+ return result;
3446
+}
3447
+
3448
+static int per_uid_read_timeouts_test(const char *mount_dir)
3449
+{
3450
+ struct test_file file = {
3451
+ .name = "file",
3452
+ .size = 16 * INCFS_DATA_FILE_BLOCK_SIZE
3453
+ };
3454
+
3455
+ int result = TEST_FAILURE;
3456
+ char *backing_dir = NULL;
3457
+ int pid = -1;
3458
+ int cmd_fd = -1;
3459
+ char *filename = NULL;
3460
+ int fd = -1;
3461
+ struct timespec start;
3462
+ char buffer[4096];
3463
+ struct incfs_per_uid_read_timeouts purt_get[1];
3464
+ struct incfs_get_read_timeouts_args grt = {
3465
+ ptr_to_u64(purt_get),
3466
+ sizeof(purt_get)
3467
+ };
3468
+ struct incfs_per_uid_read_timeouts purt_set[] = {
3469
+ {
3470
+ .uid = 0,
3471
+ .min_time_us = 1000000,
3472
+ .min_pending_time_us = 2000000,
3473
+ .max_pending_time_us = 3000000,
3474
+ },
3475
+ };
3476
+ struct incfs_set_read_timeouts_args srt = {
3477
+ ptr_to_u64(purt_set),
3478
+ sizeof(purt_set)
3479
+ };
3480
+ int status;
3481
+
3482
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3483
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
3484
+ "read_timeout_ms=1000,readahead=0", false), 0);
3485
+
3486
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3487
+ TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size,
3488
+ NULL), 0);
3489
+
3490
+ TEST(filename = concat_file_name(mount_dir, file.name), filename);
3491
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3492
+ TESTEQUAL(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC), 0);
3493
+
3494
+ /* Default mount options read failure is 1000 */
3495
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3496
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3497
+ TESTEQUAL(is_close(&start, 1000), 0);
3498
+
3499
+ grt.timeouts_array_size = 0;
3500
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
3501
+ TESTEQUAL(grt.timeouts_array_size_out, 0);
3502
+
3503
+ /* Set it to 3000 */
3504
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3505
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3506
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3507
+ TESTEQUAL(is_close(&start, 3000), 0);
3508
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), -1);
3509
+ TESTEQUAL(errno, E2BIG);
3510
+ TESTEQUAL(grt.timeouts_array_size_out, sizeof(purt_get));
3511
+ grt.timeouts_array_size = sizeof(purt_get);
3512
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
3513
+ TESTEQUAL(grt.timeouts_array_size_out, sizeof(purt_get));
3514
+ TESTEQUAL(purt_get[0].uid, purt_set[0].uid);
3515
+ TESTEQUAL(purt_get[0].min_time_us, purt_set[0].min_time_us);
3516
+ TESTEQUAL(purt_get[0].min_pending_time_us,
3517
+ purt_set[0].min_pending_time_us);
3518
+ TESTEQUAL(purt_get[0].max_pending_time_us,
3519
+ purt_set[0].max_pending_time_us);
3520
+
3521
+ /* Still 1000 in UID 2 */
3522
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3523
+ TEST(pid = fork(), pid != -1);
3524
+ if (pid == 0) {
3525
+ TESTEQUAL(setuid(2), 0);
3526
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3527
+ exit(0);
3528
+ }
3529
+ TESTNE(wait(&status), -1);
3530
+ TESTEQUAL(WEXITSTATUS(status), 0);
3531
+ TESTEQUAL(is_close(&start, 1000), 0);
3532
+
3533
+ /* Set it to default */
3534
+ purt_set[0].max_pending_time_us = UINT32_MAX;
3535
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3536
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3537
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3538
+ TESTEQUAL(is_close(&start, 1000), 0);
3539
+
3540
+ /* Test min read time */
3541
+ TESTEQUAL(emit_test_block(mount_dir, &file, 0), 0);
3542
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3543
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), sizeof(buffer));
3544
+ TESTEQUAL(is_close(&start, 1000), 0);
3545
+
3546
+ /* Test min pending time */
3547
+ purt_set[0].uid = 2;
3548
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3549
+ TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3550
+ TEST(pid = fork(), pid != -1);
3551
+ if (pid == 0) {
3552
+ TESTEQUAL(setuid(2), 0);
3553
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), sizeof(buffer)),
3554
+ sizeof(buffer));
3555
+ exit(0);
3556
+ }
3557
+ sleep(1);
3558
+ TESTEQUAL(emit_test_block(mount_dir, &file, 1), 0);
3559
+ TESTNE(wait(&status), -1);
3560
+ TESTEQUAL(WEXITSTATUS(status), 0);
3561
+ TESTEQUAL(is_close(&start, 2000), 0);
3562
+
3563
+ /* Clear timeouts */
3564
+ srt.timeouts_array_size = 0;
3565
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3566
+ grt.timeouts_array_size = 0;
3567
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
3568
+ TESTEQUAL(grt.timeouts_array_size_out, 0);
3569
+
3570
+ result = TEST_SUCCESS;
3571
+out:
3572
+ close(fd);
3573
+
3574
+ if (pid == 0)
3575
+ exit(result);
3576
+
3577
+ free(filename);
3578
+ close(cmd_fd);
3579
+ umount(mount_dir);
3580
+ free(backing_dir);
3581
+ return result;
3582
+}
3583
+
3584
+#define DIRS 3
3585
+static int inotify_test(const char *mount_dir)
3586
+{
3587
+ const char *mapped_file_name = "mapped_name";
3588
+ struct test_file file = {
3589
+ .name = "file",
3590
+ .size = 16 * INCFS_DATA_FILE_BLOCK_SIZE
3591
+ };
3592
+
3593
+ int result = TEST_FAILURE;
3594
+ char *backing_dir = NULL, *index_dir = NULL, *incomplete_dir = NULL;
3595
+ char *file_name = NULL;
3596
+ int cmd_fd = -1;
3597
+ int notify_fd = -1;
3598
+ int wds[DIRS];
3599
+ char buffer[DIRS * (sizeof(struct inotify_event) + NAME_MAX + 1)];
3600
+ char *ptr = buffer;
3601
+ struct inotify_event *event;
3602
+ struct inotify_event *events[DIRS] = {};
3603
+ const char *names[DIRS] = {};
3604
+ int res;
3605
+ char id[sizeof(incfs_uuid_t) * 2 + 1];
3606
+ struct incfs_create_mapped_file_args mfa;
3607
+
3608
+ /* File creation triggers inotify events in .index and .incomplete? */
3609
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3610
+ TEST(index_dir = concat_file_name(mount_dir, ".index"), index_dir);
3611
+ TEST(incomplete_dir = concat_file_name(mount_dir, ".incomplete"),
3612
+ incomplete_dir);
3613
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 50), 0);
3614
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3615
+ TEST(notify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC),
3616
+ notify_fd != -1);
3617
+ TEST(wds[0] = inotify_add_watch(notify_fd, mount_dir,
3618
+ IN_CREATE | IN_DELETE),
3619
+ wds[0] != -1);
3620
+ TEST(wds[1] = inotify_add_watch(notify_fd, index_dir,
3621
+ IN_CREATE | IN_DELETE),
3622
+ wds[1] != -1);
3623
+ TEST(wds[2] = inotify_add_watch(notify_fd, incomplete_dir,
3624
+ IN_CREATE | IN_DELETE),
3625
+ wds[2] != -1);
3626
+ TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size,
3627
+ NULL), 0);
3628
+ TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3629
+
3630
+ while (ptr < buffer + res) {
3631
+ int i;
3632
+
3633
+ event = (struct inotify_event *) ptr;
3634
+ TESTCOND(ptr + sizeof(*event) <= buffer + res);
3635
+ for (i = 0; i < DIRS; ++i)
3636
+ if (event->wd == wds[i]) {
3637
+ TESTEQUAL(events[i], NULL);
3638
+ events[i] = event;
3639
+ ptr += sizeof(*event);
3640
+ names[i] = ptr;
3641
+ ptr += events[i]->len;
3642
+ TESTCOND(ptr <= buffer + res);
3643
+ break;
3644
+ }
3645
+ TESTCOND(i < DIRS);
3646
+ }
3647
+
3648
+ TESTNE(events[0], NULL);
3649
+ TESTNE(events[1], NULL);
3650
+ TESTNE(events[2], NULL);
3651
+
3652
+ bin2hex(id, file.id.bytes, sizeof(incfs_uuid_t));
3653
+
3654
+ TESTEQUAL(events[0]->mask, IN_CREATE);
3655
+ TESTEQUAL(events[1]->mask, IN_CREATE);
3656
+ TESTEQUAL(events[2]->mask, IN_CREATE);
3657
+ TESTEQUAL(strcmp(names[0], file.name), 0);
3658
+ TESTEQUAL(strcmp(names[1], id), 0);
3659
+ TESTEQUAL(strcmp(names[2], id), 0);
3660
+
3661
+ /* Creating a mapped file triggers inotify event */
3662
+ mfa = (struct incfs_create_mapped_file_args) {
3663
+ .size = INCFS_DATA_FILE_BLOCK_SIZE,
3664
+ .mode = 0664,
3665
+ .file_name = ptr_to_u64(mapped_file_name),
3666
+ .source_file_id = file.id,
3667
+ .source_offset = INCFS_DATA_FILE_BLOCK_SIZE,
3668
+ };
3669
+
3670
+ TEST(res = ioctl(cmd_fd, INCFS_IOC_CREATE_MAPPED_FILE, &mfa),
3671
+ res != -1);
3672
+ TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3673
+ event = (struct inotify_event *) buffer;
3674
+ TESTEQUAL(event->wd, wds[0]);
3675
+ TESTEQUAL(event->mask, IN_CREATE);
3676
+ TESTEQUAL(strcmp(event->name, mapped_file_name), 0);
3677
+
3678
+ /* File completion triggers inotify event in .incomplete? */
3679
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
3680
+ TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3681
+ event = (struct inotify_event *) buffer;
3682
+ TESTEQUAL(event->wd, wds[2]);
3683
+ TESTEQUAL(event->mask, IN_DELETE);
3684
+ TESTEQUAL(strcmp(event->name, id), 0);
3685
+
3686
+ /* File unlinking triggers inotify event in .index? */
3687
+ TEST(file_name = concat_file_name(mount_dir, file.name), file_name);
3688
+ TESTEQUAL(unlink(file_name), 0);
3689
+ TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3690
+ memset(events, 0, sizeof(events));
3691
+ memset(names, 0, sizeof(names));
3692
+ for (ptr = buffer; ptr < buffer + res;) {
3693
+ event = (struct inotify_event *) ptr;
3694
+ int i;
3695
+
3696
+ TESTCOND(ptr + sizeof(*event) <= buffer + res);
3697
+ for (i = 0; i < DIRS; ++i)
3698
+ if (event->wd == wds[i]) {
3699
+ TESTEQUAL(events[i], NULL);
3700
+ events[i] = event;
3701
+ ptr += sizeof(*event);
3702
+ names[i] = ptr;
3703
+ ptr += events[i]->len;
3704
+ TESTCOND(ptr <= buffer + res);
3705
+ break;
3706
+ }
3707
+ TESTCOND(i < DIRS);
3708
+ }
3709
+
3710
+ TESTNE(events[0], NULL);
3711
+ TESTNE(events[1], NULL);
3712
+ TESTEQUAL(events[2], NULL);
3713
+
3714
+ TESTEQUAL(events[0]->mask, IN_DELETE);
3715
+ TESTEQUAL(events[1]->mask, IN_DELETE);
3716
+ TESTEQUAL(strcmp(names[0], file.name), 0);
3717
+ TESTEQUAL(strcmp(names[1], id), 0);
3718
+
3719
+ result = TEST_SUCCESS;
3720
+out:
3721
+ free(file_name);
3722
+ close(notify_fd);
3723
+ close(cmd_fd);
3724
+ umount(mount_dir);
3725
+ free(backing_dir);
3726
+ free(index_dir);
3727
+ free(incomplete_dir);
3728
+ return result;
3729
+}
3730
+
3731
+static EVP_PKEY *create_key(void)
3732
+{
3733
+ EVP_PKEY *pkey = NULL;
3734
+ RSA *rsa = NULL;
3735
+ BIGNUM *bn = NULL;
3736
+
3737
+ pkey = EVP_PKEY_new();
3738
+ if (!pkey)
3739
+ goto fail;
3740
+
3741
+ bn = BN_new();
3742
+ BN_set_word(bn, RSA_F4);
3743
+
3744
+ rsa = RSA_new();
3745
+ if (!rsa)
3746
+ goto fail;
3747
+
3748
+ RSA_generate_key_ex(rsa, 4096, bn, NULL);
3749
+ EVP_PKEY_assign_RSA(pkey, rsa);
3750
+
3751
+ BN_free(bn);
3752
+ return pkey;
3753
+
3754
+fail:
3755
+ BN_free(bn);
3756
+ EVP_PKEY_free(pkey);
3757
+ return NULL;
3758
+}
3759
+
3760
+static X509 *get_cert(EVP_PKEY *key)
3761
+{
3762
+ X509 *x509 = NULL;
3763
+ X509_NAME *name = NULL;
3764
+
3765
+ x509 = X509_new();
3766
+ if (!x509)
3767
+ return NULL;
3768
+
3769
+ ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
3770
+ X509_gmtime_adj(X509_get_notBefore(x509), 0);
3771
+ X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
3772
+ X509_set_pubkey(x509, key);
3773
+
3774
+ name = X509_get_subject_name(x509);
3775
+ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
3776
+ (const unsigned char *)"US", -1, -1, 0);
3777
+ X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC,
3778
+ (const unsigned char *)"CA", -1, -1, 0);
3779
+ X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC,
3780
+ (const unsigned char *)"San Jose", -1, -1, 0);
3781
+ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
3782
+ (const unsigned char *)"Example", -1, -1, 0);
3783
+ X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC,
3784
+ (const unsigned char *)"Org", -1, -1, 0);
3785
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
3786
+ (const unsigned char *)"www.example.com", -1, -1, 0);
3787
+ X509_set_issuer_name(x509, name);
3788
+
3789
+ if (!X509_sign(x509, key, EVP_sha256()))
3790
+ return NULL;
3791
+
3792
+ return x509;
3793
+}
3794
+
3795
+static int sign(EVP_PKEY *key, X509 *cert, const char *data, size_t len,
3796
+ unsigned char **sig, size_t *sig_len)
3797
+{
3798
+ const int pkcs7_flags = PKCS7_BINARY | PKCS7_NOATTR | PKCS7_PARTIAL |
3799
+ PKCS7_DETACHED;
3800
+ const EVP_MD *md = EVP_sha256();
3801
+
3802
+ int result = TEST_FAILURE;
3803
+
3804
+ BIO *bio = NULL;
3805
+ PKCS7 *p7 = NULL;
3806
+ unsigned char *bio_buffer;
3807
+
3808
+ TEST(bio = BIO_new_mem_buf(data, len), bio);
3809
+ TEST(p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags), p7);
3810
+ TESTNE(PKCS7_sign_add_signer(p7, cert, key, md, pkcs7_flags), 0);
3811
+ TESTEQUAL(PKCS7_final(p7, bio, pkcs7_flags), 1);
3812
+ TEST(*sig_len = i2d_PKCS7(p7, NULL), *sig_len);
3813
+ TEST(bio_buffer = malloc(*sig_len), bio_buffer);
3814
+ *sig = bio_buffer;
3815
+ TEST(*sig_len = i2d_PKCS7(p7, &bio_buffer), *sig_len);
3816
+ TESTEQUAL(PKCS7_verify(p7, NULL, NULL, bio, NULL,
3817
+ pkcs7_flags | PKCS7_NOVERIFY | PKCS7_NOSIGS), 1);
3818
+
3819
+ result = TEST_SUCCESS;
3820
+out:
3821
+ PKCS7_free(p7);
3822
+ BIO_free(bio);
3823
+ return result;
3824
+}
3825
+
3826
+static int verity_installed(const char *mount_dir, int cmd_fd, bool *installed)
3827
+{
3828
+ int result = TEST_FAILURE;
3829
+ char *filename = NULL;
3830
+ int fd = -1;
3831
+ struct test_file *file = &get_test_files_set().files[0];
3832
+
3833
+ TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id, file->size,
3834
+ NULL), 0);
3835
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
3836
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3837
+ TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, NULL), -1);
3838
+ *installed = errno != EOPNOTSUPP;
3839
+
3840
+ result = TEST_SUCCESS;
3841
+out:
3842
+ close(fd);
3843
+ if (filename)
3844
+ remove(filename);
3845
+ free(filename);
3846
+ return result;
3847
+}
3848
+
3849
+static int enable_verity(const char *mount_dir, struct test_file *file,
3850
+ EVP_PKEY *key, X509 *cert, bool use_signatures)
3851
+{
3852
+ int result = TEST_FAILURE;
3853
+ char *filename = NULL;
3854
+ int fd = -1;
3855
+ struct fsverity_enable_arg fear = {
3856
+ .version = 1,
3857
+ .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
3858
+ .block_size = INCFS_DATA_FILE_BLOCK_SIZE,
3859
+ .sig_size = 0,
3860
+ .sig_ptr = 0,
3861
+ };
3862
+ struct {
3863
+ __u8 version; /* must be 1 */
3864
+ __u8 hash_algorithm; /* Merkle tree hash algorithm */
3865
+ __u8 log_blocksize; /* log2 of size of data and tree blocks */
3866
+ __u8 salt_size; /* size of salt in bytes; 0 if none */
3867
+ __le32 sig_size; /* must be 0 */
3868
+ __le64 data_size; /* size of file the Merkle tree is built over */
3869
+ __u8 root_hash[64]; /* Merkle tree root hash */
3870
+ __u8 salt[32]; /* salt prepended to each hashed block */
3871
+ __u8 __reserved[144]; /* must be 0's */
3872
+ } __packed fsverity_descriptor = {
3873
+ .version = 1,
3874
+ .hash_algorithm = 1,
3875
+ .log_blocksize = 12,
3876
+ .data_size = file->size,
3877
+ };
3878
+ struct {
3879
+ char magic[8]; /* must be "FSVerity" */
3880
+ __le16 digest_algorithm;
3881
+ __le16 digest_size;
3882
+ __u8 digest[32];
3883
+ } __packed fsverity_signed_digest = {
3884
+ .digest_algorithm = 1,
3885
+ .digest_size = 32
3886
+ };
3887
+ unsigned char *sig = NULL;
3888
+ size_t sig_size = 0;
3889
+ uint64_t flags;
3890
+ struct statx statxbuf = {};
3891
+
3892
+ memcpy(fsverity_signed_digest.magic, "FSVerity", 8);
3893
+
3894
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
3895
+ TESTEQUAL(syscall(__NR_statx, AT_FDCWD, filename, 0, STATX_ALL,
3896
+ &statxbuf), 0);
3897
+ TESTEQUAL(statxbuf.stx_attributes_mask & STATX_ATTR_VERITY,
3898
+ STATX_ATTR_VERITY);
3899
+ TESTEQUAL(statxbuf.stx_attributes & STATX_ATTR_VERITY, 0);
3900
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3901
+ TESTEQUAL(ioctl(fd, FS_IOC_GETFLAGS, &flags), 0);
3902
+ TESTEQUAL(flags & FS_VERITY_FL, 0);
3903
+
3904
+ /* First try to enable verity with random digest */
3905
+ if (key) {
3906
+ TESTEQUAL(sign(key, cert, (void *)&fsverity_signed_digest,
3907
+ sizeof(fsverity_signed_digest), &sig, &sig_size),
3908
+ 0);
3909
+
3910
+ fear.sig_size = sig_size;
3911
+ fear.sig_ptr = ptr_to_u64(sig);
3912
+ TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, &fear), -1);
3913
+ }
3914
+
3915
+ /* Now try with correct digest */
3916
+ memcpy(fsverity_descriptor.root_hash, file->root_hash, 32);
3917
+ sha256((char *)&fsverity_descriptor, sizeof(fsverity_descriptor),
3918
+ (char *)fsverity_signed_digest.digest);
3919
+
3920
+ if (ioctl(fd, FS_IOC_ENABLE_VERITY, NULL) == -1 &&
3921
+ errno == EOPNOTSUPP) {
3922
+ result = TEST_SUCCESS;
3923
+ goto out;
3924
+ }
3925
+
3926
+ free(sig);
3927
+ sig = NULL;
3928
+
3929
+ if (key)
3930
+ TESTEQUAL(sign(key, cert, (void *)&fsverity_signed_digest,
3931
+ sizeof(fsverity_signed_digest),
3932
+ &sig, &sig_size),
3933
+ 0);
3934
+
3935
+ if (use_signatures) {
3936
+ fear.sig_size = sig_size;
3937
+ file->verity_sig_size = sig_size;
3938
+ fear.sig_ptr = ptr_to_u64(sig);
3939
+ file->verity_sig = sig;
3940
+ sig = NULL;
3941
+ } else {
3942
+ fear.sig_size = 0;
3943
+ fear.sig_ptr = 0;
3944
+ }
3945
+ TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, &fear), 0);
3946
+
3947
+ result = TEST_SUCCESS;
3948
+out:
3949
+ free(sig);
3950
+ close(fd);
3951
+ free(filename);
3952
+ return result;
3953
+}
3954
+
3955
+static int memzero(const unsigned char *buf, size_t size)
3956
+{
3957
+ size_t i;
3958
+
3959
+ for (i = 0; i < size; ++i)
3960
+ if (buf[i])
3961
+ return -1;
3962
+ return 0;
3963
+}
3964
+
3965
+static int validate_verity(const char *mount_dir, struct test_file *file)
3966
+{
3967
+ int result = TEST_FAILURE;
3968
+ char *filename = concat_file_name(mount_dir, file->name);
3969
+ int fd = -1;
3970
+ uint64_t flags;
3971
+ struct fsverity_digest *digest;
3972
+ struct statx statxbuf = {};
3973
+ struct fsverity_read_metadata_arg frma = {};
3974
+ uint8_t *buf = NULL;
3975
+ struct fsverity_descriptor desc;
3976
+
3977
+ TEST(digest = malloc(sizeof(struct fsverity_digest) +
3978
+ INCFS_MAX_HASH_SIZE), digest != NULL);
3979
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
3980
+ TESTEQUAL(syscall(__NR_statx, AT_FDCWD, filename, 0, STATX_ALL,
3981
+ &statxbuf), 0);
3982
+ TESTEQUAL(statxbuf.stx_attributes & STATX_ATTR_VERITY,
3983
+ STATX_ATTR_VERITY);
3984
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3985
+ TESTEQUAL(ioctl(fd, FS_IOC_GETFLAGS, &flags), 0);
3986
+ TESTEQUAL(flags & FS_VERITY_FL, FS_VERITY_FL);
3987
+ digest->digest_size = INCFS_MAX_HASH_SIZE;
3988
+ TESTEQUAL(ioctl(fd, FS_IOC_MEASURE_VERITY, digest), 0);
3989
+ TESTEQUAL(digest->digest_algorithm, FS_VERITY_HASH_ALG_SHA256);
3990
+ TESTEQUAL(digest->digest_size, 32);
3991
+
3992
+ if (file->verity_sig) {
3993
+ TEST(buf = malloc(file->verity_sig_size), buf);
3994
+ frma = (struct fsverity_read_metadata_arg) {
3995
+ .metadata_type = FS_VERITY_METADATA_TYPE_SIGNATURE,
3996
+ .length = file->verity_sig_size,
3997
+ .buf_ptr = ptr_to_u64(buf),
3998
+ };
3999
+ TESTEQUAL(ioctl(fd, FS_IOC_READ_VERITY_METADATA, &frma),
4000
+ file->verity_sig_size);
4001
+ TESTEQUAL(memcmp(buf, file->verity_sig, file->verity_sig_size),
4002
+ 0);
4003
+ } else {
4004
+ frma = (struct fsverity_read_metadata_arg) {
4005
+ .metadata_type = FS_VERITY_METADATA_TYPE_SIGNATURE,
4006
+ };
4007
+ TESTEQUAL(ioctl(fd, FS_IOC_READ_VERITY_METADATA, &frma), -1);
4008
+ TESTEQUAL(errno, ENODATA);
4009
+ }
4010
+
4011
+ frma = (struct fsverity_read_metadata_arg) {
4012
+ .metadata_type = FS_VERITY_METADATA_TYPE_DESCRIPTOR,
4013
+ .length = sizeof(desc),
4014
+ .buf_ptr = ptr_to_u64(&desc),
4015
+ };
4016
+ TESTEQUAL(ioctl(fd, FS_IOC_READ_VERITY_METADATA, &frma),
4017
+ sizeof(desc));
4018
+ TESTEQUAL(desc.version, 1);
4019
+ TESTEQUAL(desc.hash_algorithm, FS_VERITY_HASH_ALG_SHA256);
4020
+ TESTEQUAL(desc.log_blocksize, ilog2(INCFS_DATA_FILE_BLOCK_SIZE));
4021
+ TESTEQUAL(desc.salt_size, 0);
4022
+ TESTEQUAL(desc.__reserved_0x04, 0);
4023
+ TESTEQUAL(desc.data_size, file->size);
4024
+ TESTEQUAL(memcmp(desc.root_hash, file->root_hash, SHA256_DIGEST_SIZE),
4025
+ 0);
4026
+ TESTEQUAL(memzero(desc.root_hash + SHA256_DIGEST_SIZE,
4027
+ sizeof(desc.root_hash) - SHA256_DIGEST_SIZE), 0);
4028
+ TESTEQUAL(memzero(desc.salt, sizeof(desc.salt)), 0);
4029
+ TESTEQUAL(memzero(desc.__reserved, sizeof(desc.__reserved)), 0);
4030
+
4031
+ result = TEST_SUCCESS;
4032
+out:
4033
+ free(buf);
4034
+ close(fd);
4035
+ free(filename);
4036
+ free(digest);
4037
+ return result;
4038
+}
4039
+
4040
+static int verity_test_optional_sigs(const char *mount_dir, bool use_signatures)
4041
+{
4042
+ int result = TEST_FAILURE;
4043
+ char *backing_dir = NULL;
4044
+ bool installed;
4045
+ int cmd_fd = -1;
4046
+ int i;
4047
+ struct test_files_set test = get_test_files_set();
4048
+ const int file_num = test.files_count;
4049
+ EVP_PKEY *key = NULL;
4050
+ X509 *cert = NULL;
4051
+ BIO *mem = NULL;
4052
+ long len;
4053
+ void *ptr;
4054
+ FILE *proc_key_fd = NULL;
4055
+ char *line = NULL;
4056
+ size_t read = 0;
4057
+ int key_id = -1;
4058
+
4059
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4060
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
4061
+ 0);
4062
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4063
+ TESTEQUAL(verity_installed(mount_dir, cmd_fd, &installed), 0);
4064
+ if (!installed) {
4065
+ result = TEST_SUCCESS;
4066
+ goto out;
4067
+ }
4068
+ TEST(key = create_key(), key);
4069
+ TEST(cert = get_cert(key), cert);
4070
+
4071
+ TEST(proc_key_fd = fopen("/proc/keys", "r"), proc_key_fd != NULL);
4072
+ while (getline(&line, &read, proc_key_fd) != -1)
4073
+ if (strstr(line, ".fs-verity"))
4074
+ key_id = strtol(line, NULL, 16);
4075
+
4076
+ TEST(mem = BIO_new(BIO_s_mem()), mem != NULL);
4077
+ TESTEQUAL(i2d_X509_bio(mem, cert), 1);
4078
+ TEST(len = BIO_get_mem_data(mem, &ptr), len != 0);
4079
+ TESTCOND(key_id == -1
4080
+ || syscall(__NR_add_key, "asymmetric", "test:key", ptr, len,
4081
+ key_id) != -1);
4082
+
4083
+ for (i = 0; i < file_num; i++) {
4084
+ struct test_file *file = &test.files[i];
4085
+
4086
+ build_mtree(file);
4087
+ TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
4088
+ file->size, file->root_hash,
4089
+ file->sig.add_data), 0);
4090
+
4091
+ TESTEQUAL(load_hash_tree(mount_dir, file), 0);
4092
+ TESTEQUAL(enable_verity(mount_dir, file, key, cert,
4093
+ use_signatures),
4094
+ 0);
4095
+ }
4096
+
4097
+ for (i = 0; i < file_num; i++)
4098
+ TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
4099
+
4100
+ close(cmd_fd);
4101
+ cmd_fd = -1;
4102
+ TESTEQUAL(umount(mount_dir), 0);
4103
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
4104
+ 0);
4105
+
4106
+ for (i = 0; i < file_num; i++)
4107
+ TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
4108
+
4109
+ result = TEST_SUCCESS;
4110
+out:
4111
+ for (i = 0; i < file_num; i++) {
4112
+ struct test_file *file = &test.files[i];
4113
+
4114
+ free(file->mtree);
4115
+ free(file->verity_sig);
4116
+
4117
+ file->mtree = NULL;
4118
+ file->verity_sig = NULL;
4119
+ }
4120
+
4121
+ free(line);
4122
+ BIO_free(mem);
4123
+ X509_free(cert);
4124
+ EVP_PKEY_free(key);
4125
+ fclose(proc_key_fd);
4126
+ close(cmd_fd);
4127
+ umount(mount_dir);
4128
+ free(backing_dir);
4129
+ return result;
4130
+}
4131
+
4132
+static int verity_test(const char *mount_dir)
4133
+{
4134
+ int result = TEST_FAILURE;
4135
+
4136
+ TESTEQUAL(verity_test_optional_sigs(mount_dir, true), TEST_SUCCESS);
4137
+ TESTEQUAL(verity_test_optional_sigs(mount_dir, false), TEST_SUCCESS);
4138
+ result = TEST_SUCCESS;
4139
+out:
4140
+ return result;
4141
+}
4142
+
4143
+static int verity_file_valid(const char *mount_dir, struct test_file *file)
4144
+{
4145
+ int result = TEST_FAILURE;
4146
+ char *filename = NULL;
4147
+ int fd = -1;
4148
+ uint8_t buffer[INCFS_DATA_FILE_BLOCK_SIZE];
4149
+ struct incfs_get_file_sig_args gfsa = {
4150
+ .file_signature = ptr_to_u64(buffer),
4151
+ .file_signature_buf_size = sizeof(buffer),
4152
+ };
4153
+ int i;
4154
+
4155
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
4156
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4157
+ TESTEQUAL(ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &gfsa), 0);
4158
+ for (i = 0; i < file->size; i += sizeof(buffer))
4159
+ TESTEQUAL(pread(fd, buffer, sizeof(buffer), i),
4160
+ file->size - i > sizeof(buffer) ?
4161
+ sizeof(buffer) : file->size - i);
4162
+
4163
+ result = TEST_SUCCESS;
4164
+out:
4165
+ close(fd);
4166
+ free(filename);
4167
+ return result;
4168
+}
4169
+
4170
+static int enable_verity_test(const char *mount_dir)
4171
+{
4172
+ int result = TEST_FAILURE;
4173
+ char *backing_dir = NULL;
4174
+ bool installed;
4175
+ int cmd_fd = -1;
4176
+ struct test_files_set test = get_test_files_set();
4177
+ int i;
4178
+
4179
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4180
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4181
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4182
+ TESTEQUAL(verity_installed(mount_dir, cmd_fd, &installed), 0);
4183
+ if (!installed) {
4184
+ result = TEST_SUCCESS;
4185
+ goto out;
4186
+ }
4187
+ for (i = 0; i < test.files_count; ++i) {
4188
+ struct test_file *file = &test.files[i];
4189
+
4190
+ TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
4191
+ file->size, NULL), 0);
4192
+ TESTEQUAL(emit_test_file_data(mount_dir, file), 0);
4193
+ TESTEQUAL(enable_verity(mount_dir, file, NULL, NULL, false), 0);
4194
+ }
4195
+
4196
+ /* Check files are valid on disk */
4197
+ close(cmd_fd);
4198
+ cmd_fd = -1;
4199
+ TESTEQUAL(umount(mount_dir), 0);
4200
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4201
+ for (i = 0; i < test.files_count; ++i)
4202
+ TESTEQUAL(verity_file_valid(mount_dir, &test.files[i]), 0);
4203
+
4204
+ result = TEST_SUCCESS;
4205
+out:
4206
+ close(cmd_fd);
4207
+ umount(mount_dir);
4208
+ free(backing_dir);
4209
+ return result;
4210
+}
4211
+
4212
+static int mmap_test(const char *mount_dir)
4213
+{
4214
+ int result = TEST_FAILURE;
4215
+ char *backing_dir = NULL;
4216
+ int cmd_fd = -1;
4217
+ /*
4218
+ * File is big enough to have a two layer tree with two hashes in the
4219
+ * higher level, so we can corrupt the second one
4220
+ */
4221
+ int shas_per_block = INCFS_DATA_FILE_BLOCK_SIZE / SHA256_DIGEST_SIZE;
4222
+ struct test_file file = {
4223
+ .name = "file",
4224
+ .size = INCFS_DATA_FILE_BLOCK_SIZE * shas_per_block * 2,
4225
+ };
4226
+ char *filename = NULL;
4227
+ int fd = -1;
4228
+ char *addr = (void *)-1;
4229
+
4230
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4231
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4232
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4233
+
4234
+ TESTEQUAL(build_mtree(&file), 0);
4235
+ file.mtree[1].data[INCFS_DATA_FILE_BLOCK_SIZE] ^= 0xff;
4236
+ TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file.name, &file.id,
4237
+ file.size, file.root_hash,
4238
+ file.sig.add_data), 0);
4239
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4240
+ TESTEQUAL(load_hash_tree(mount_dir, &file), 0);
4241
+ TEST(filename = concat_file_name(mount_dir, file.name), filename);
4242
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4243
+ TEST(addr = mmap(NULL, file.size, PROT_READ, MAP_PRIVATE, fd, 0),
4244
+ addr != (void *) -1);
4245
+ TESTEQUAL(mlock(addr, INCFS_DATA_FILE_BLOCK_SIZE), 0);
4246
+ TESTEQUAL(munlock(addr, INCFS_DATA_FILE_BLOCK_SIZE), 0);
4247
+ TESTEQUAL(mlock(addr + shas_per_block * INCFS_DATA_FILE_BLOCK_SIZE,
4248
+ INCFS_DATA_FILE_BLOCK_SIZE), -1);
4249
+ TESTEQUAL(mlock(addr + (shas_per_block - 1) *
4250
+ INCFS_DATA_FILE_BLOCK_SIZE,
4251
+ INCFS_DATA_FILE_BLOCK_SIZE), 0);
4252
+ TESTEQUAL(munlock(addr + (shas_per_block - 1) *
4253
+ INCFS_DATA_FILE_BLOCK_SIZE,
4254
+ INCFS_DATA_FILE_BLOCK_SIZE), 0);
4255
+ TESTEQUAL(mlock(addr + (shas_per_block - 1) *
4256
+ INCFS_DATA_FILE_BLOCK_SIZE,
4257
+ INCFS_DATA_FILE_BLOCK_SIZE * 2), -1);
4258
+ TESTEQUAL(munmap(addr, file.size), 0);
4259
+
4260
+ result = TEST_SUCCESS;
4261
+out:
4262
+ free(file.mtree);
4263
+ close(fd);
4264
+ free(filename);
4265
+ close(cmd_fd);
4266
+ umount(mount_dir);
4267
+ free(backing_dir);
4268
+ return result;
4269
+}
4270
+
4271
+static int truncate_test(const char *mount_dir)
4272
+{
4273
+ int result = TEST_FAILURE;
4274
+ char *backing_dir = NULL;
4275
+ int cmd_fd = -1;
4276
+ struct test_file file = {
4277
+ .name = "file",
4278
+ .size = INCFS_DATA_FILE_BLOCK_SIZE,
4279
+ };
4280
+ char *backing_file = NULL;
4281
+ int fd = -1;
4282
+ struct stat st;
4283
+
4284
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4285
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4286
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4287
+ TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4288
+ 0);
4289
+ TEST(backing_file = concat_file_name(backing_dir, file.name),
4290
+ backing_file);
4291
+ TEST(fd = open(backing_file, O_RDWR | O_CLOEXEC), fd != -1);
4292
+ TESTEQUAL(stat(backing_file, &st), 0);
4293
+ TESTCOND(st.st_blocks < 128);
4294
+ TESTEQUAL(fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, 1 << 24), 0);
4295
+ TESTEQUAL(stat(backing_file, &st), 0);
4296
+ TESTCOND(st.st_blocks > 32768);
4297
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4298
+ TESTEQUAL(stat(backing_file, &st), 0);
4299
+ TESTCOND(st.st_blocks < 128);
4300
+
4301
+ result = TEST_SUCCESS;
4302
+out:
4303
+ close(fd);
4304
+ free(backing_file);
4305
+ close(cmd_fd);
4306
+ umount(mount_dir);
4307
+ free(backing_dir);
4308
+ return result;
4309
+}
4310
+
4311
+static int stat_file_test(const char *mount_dir, int cmd_fd,
4312
+ struct test_file *file)
4313
+{
4314
+ int result = TEST_FAILURE;
4315
+ struct stat st;
4316
+ char *filename = NULL;
4317
+
4318
+ TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
4319
+ file->size, NULL), 0);
4320
+ TEST(filename = concat_file_name(mount_dir, file->name), filename);
4321
+ TESTEQUAL(stat(filename, &st), 0);
4322
+ TESTCOND(st.st_blocks < 32);
4323
+ TESTEQUAL(emit_test_file_data(mount_dir, file), 0);
4324
+ TESTEQUAL(stat(filename, &st), 0);
4325
+ TESTCOND(st.st_blocks > file->size / 512);
4326
+
4327
+ result = TEST_SUCCESS;
4328
+out:
4329
+ free(filename);
4330
+ return result;
4331
+}
4332
+
4333
+static int stat_test(const char *mount_dir)
4334
+{
4335
+ int result = TEST_FAILURE;
4336
+ char *backing_dir = NULL;
4337
+ int cmd_fd = -1;
4338
+ int i;
4339
+ struct test_files_set test = get_test_files_set();
4340
+ const int file_num = test.files_count;
4341
+
4342
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4343
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4344
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4345
+
4346
+ for (i = 0; i < file_num; i++) {
4347
+ struct test_file *file = &test.files[i];
4348
+
4349
+ TESTEQUAL(stat_file_test(mount_dir, cmd_fd, file), 0);
4350
+ }
4351
+
4352
+ result = TEST_SUCCESS;
4353
+out:
4354
+ close(cmd_fd);
4355
+ umount(mount_dir);
4356
+ free(backing_dir);
4357
+ return result;
4358
+}
4359
+
4360
+#define SYSFS_DIR "/sys/fs/incremental-fs/instances/test_node/"
4361
+
4362
+static int sysfs_test_value(const char *name, uint64_t value)
4363
+{
4364
+ int result = TEST_FAILURE;
4365
+ char *filename = NULL;
4366
+ FILE *file = NULL;
4367
+ uint64_t res;
4368
+
4369
+ TEST(filename = concat_file_name(SYSFS_DIR, name), filename);
4370
+ TEST(file = fopen(filename, "re"), file);
4371
+ TESTEQUAL(fscanf(file, "%lu", &res), 1);
4372
+ TESTEQUAL(res, value);
4373
+
4374
+ result = TEST_SUCCESS;
4375
+out:
4376
+ if (file)
4377
+ fclose(file);
4378
+ free(filename);
4379
+ return result;
4380
+}
4381
+
4382
+static int sysfs_test_value_range(const char *name, uint64_t low, uint64_t high)
4383
+{
4384
+ int result = TEST_FAILURE;
4385
+ char *filename = NULL;
4386
+ FILE *file = NULL;
4387
+ uint64_t res;
4388
+
4389
+ TEST(filename = concat_file_name(SYSFS_DIR, name), filename);
4390
+ TEST(file = fopen(filename, "re"), file);
4391
+ TESTEQUAL(fscanf(file, "%lu", &res), 1);
4392
+ TESTCOND(res >= low && res <= high);
4393
+
4394
+ result = TEST_SUCCESS;
4395
+out:
4396
+ if (file)
4397
+ fclose(file);
4398
+ free(filename);
4399
+ return result;
4400
+}
4401
+
4402
+static int ioctl_test_last_error(int cmd_fd, const incfs_uuid_t *file_id,
4403
+ int page, int error)
4404
+{
4405
+ int result = TEST_FAILURE;
4406
+ struct incfs_get_last_read_error_args glre;
4407
+
4408
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_LAST_READ_ERROR, &glre), 0);
4409
+ if (file_id)
4410
+ TESTEQUAL(memcmp(&glre.file_id_out, file_id, sizeof(*file_id)),
4411
+ 0);
4412
+
4413
+ TESTEQUAL(glre.page_out, page);
4414
+ TESTEQUAL(glre.errno_out, error);
4415
+ result = TEST_SUCCESS;
4416
+out:
4417
+ return result;
4418
+}
4419
+
4420
+static int sysfs_test(const char *mount_dir)
4421
+{
4422
+ int result = TEST_FAILURE;
4423
+ char *backing_dir = NULL;
4424
+ int cmd_fd = -1;
4425
+ struct test_file file = {
4426
+ .name = "file",
4427
+ .size = INCFS_DATA_FILE_BLOCK_SIZE,
4428
+ };
4429
+ char *filename = NULL;
4430
+ int fd = -1;
4431
+ int pid = -1;
4432
+ char buffer[32];
4433
+ char *null_buf = NULL;
4434
+ int status;
4435
+ struct incfs_per_uid_read_timeouts purt_set[] = {
4436
+ {
4437
+ .uid = 0,
4438
+ .min_time_us = 1000000,
4439
+ .min_pending_time_us = 1000000,
4440
+ .max_pending_time_us = 2000000,
4441
+ },
4442
+ };
4443
+ struct incfs_set_read_timeouts_args srt = {
4444
+ ptr_to_u64(purt_set),
4445
+ sizeof(purt_set)
4446
+ };
4447
+
4448
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4449
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "sysfs_name=test_node",
4450
+ false),
4451
+ 0);
4452
+ TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4453
+ TESTEQUAL(build_mtree(&file), 0);
4454
+ file.root_hash[0] ^= 0xff;
4455
+ TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file.name, &file.id, file.size,
4456
+ file.root_hash, file.sig.add_data),
4457
+ 0);
4458
+ TEST(filename = concat_file_name(mount_dir, file.name), filename);
4459
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4460
+ TESTEQUAL(ioctl_test_last_error(cmd_fd, NULL, 0, 0), 0);
4461
+ TESTEQUAL(sysfs_test_value("reads_failed_timed_out", 0), 0);
4462
+ TESTEQUAL(read(fd, null_buf, 1), -1);
4463
+ TESTEQUAL(ioctl_test_last_error(cmd_fd, &file.id, 0, -ETIME), 0);
4464
+ TESTEQUAL(sysfs_test_value("reads_failed_timed_out", 2), 0);
4465
+
4466
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4467
+ TESTEQUAL(sysfs_test_value("reads_failed_hash_verification", 0), 0);
4468
+ TESTEQUAL(read(fd, null_buf, 1), -1);
4469
+ TESTEQUAL(sysfs_test_value("reads_failed_hash_verification", 1), 0);
4470
+ TESTSYSCALL(close(fd));
4471
+ fd = -1;
4472
+
4473
+ TESTSYSCALL(unlink(filename));
4474
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
4475
+ "read_timeout_ms=10000,sysfs_name=test_node",
4476
+ true),
4477
+ 0);
4478
+ TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4479
+ 0);
4480
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4481
+ TESTSYSCALL(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC));
4482
+ TEST(pid = fork(), pid != -1);
4483
+ if (pid == 0) {
4484
+ TESTEQUAL(read(fd, buffer, sizeof(buffer)), sizeof(buffer));
4485
+ exit(0);
4486
+ }
4487
+ sleep(1);
4488
+ TESTEQUAL(sysfs_test_value("reads_delayed_pending", 0), 0);
4489
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4490
+ TESTNE(wait(&status), -1);
4491
+ TESTEQUAL(status, 0);
4492
+ TESTEQUAL(sysfs_test_value("reads_delayed_pending", 1), 0);
4493
+ /* Allow +/- 10% */
4494
+ TESTEQUAL(sysfs_test_value_range("reads_delayed_pending_us", 900000, 1100000),
4495
+ 0);
4496
+
4497
+ TESTSYSCALL(close(fd));
4498
+ fd = -1;
4499
+
4500
+ TESTSYSCALL(unlink(filename));
4501
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
4502
+ TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4503
+ 0);
4504
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4505
+ TESTEQUAL(sysfs_test_value("reads_delayed_min", 0), 0);
4506
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4507
+ TESTEQUAL(read(fd, buffer, sizeof(buffer)), sizeof(buffer));
4508
+ TESTEQUAL(sysfs_test_value("reads_delayed_min", 1), 0);
4509
+ /* This should be exact */
4510
+ TESTEQUAL(sysfs_test_value("reads_delayed_min_us", 1000000), 0);
4511
+
4512
+ TESTSYSCALL(close(fd));
4513
+ fd = -1;
4514
+
4515
+ TESTSYSCALL(unlink(filename));
4516
+ TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4517
+ 0);
4518
+ TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4519
+ TESTSYSCALL(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC));
4520
+ TEST(pid = fork(), pid != -1);
4521
+ if (pid == 0) {
4522
+ TESTEQUAL(read(fd, buffer, sizeof(buffer)), sizeof(buffer));
4523
+ exit(0);
4524
+ }
4525
+ usleep(500000);
4526
+ TESTEQUAL(sysfs_test_value("reads_delayed_pending", 1), 0);
4527
+ TESTEQUAL(sysfs_test_value("reads_delayed_min", 1), 0);
4528
+ TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4529
+ TESTNE(wait(&status), -1);
4530
+ TESTEQUAL(status, 0);
4531
+ TESTEQUAL(sysfs_test_value("reads_delayed_pending", 2), 0);
4532
+ TESTEQUAL(sysfs_test_value("reads_delayed_min", 2), 0);
4533
+ /* Exact 1000000 plus 500000 +/- 10% */
4534
+ TESTEQUAL(sysfs_test_value_range("reads_delayed_min_us", 1450000, 1550000), 0);
4535
+ /* Allow +/- 10% */
4536
+ TESTEQUAL(sysfs_test_value_range("reads_delayed_pending_us", 1350000, 1650000),
4537
+ 0);
4538
+
4539
+ result = TEST_SUCCESS;
4540
+out:
4541
+ if (pid == 0)
4542
+ exit(result);
4543
+ free(file.mtree);
4544
+ free(filename);
4545
+ close(fd);
4546
+ close(cmd_fd);
4547
+ umount(mount_dir);
4548
+ free(backing_dir);
4549
+ return result;
4550
+}
4551
+
4552
+static int sysfs_test_directories(bool one_present, bool two_present)
4553
+{
4554
+ int result = TEST_FAILURE;
4555
+ struct stat st;
4556
+
4557
+ TESTEQUAL(stat("/sys/fs/incremental-fs/instances/1", &st),
4558
+ one_present ? 0 : -1);
4559
+ if (one_present)
4560
+ TESTCOND(S_ISDIR(st.st_mode));
4561
+ else
4562
+ TESTEQUAL(errno, ENOENT);
4563
+ TESTEQUAL(stat("/sys/fs/incremental-fs/instances/2", &st),
4564
+ two_present ? 0 : -1);
4565
+ if (two_present)
4566
+ TESTCOND(S_ISDIR(st.st_mode));
4567
+ else
4568
+ TESTEQUAL(errno, ENOENT);
4569
+
4570
+ result = TEST_SUCCESS;
4571
+out:
4572
+ return result;
4573
+}
4574
+
4575
+static int sysfs_rename_test(const char *mount_dir)
4576
+{
4577
+ int result = TEST_FAILURE;
4578
+ char *backing_dir = NULL;
4579
+ char *mount_dir2 = NULL;
4580
+ int fd = -1;
4581
+ char c;
4582
+
4583
+ /* Mount with no node */
4584
+ TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4585
+ TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4586
+ TESTEQUAL(sysfs_test_directories(false, false), 0);
4587
+
4588
+ /* Remount with node */
4589
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "sysfs_name=1", true),
4590
+ 0);
4591
+ TESTEQUAL(sysfs_test_directories(true, false), 0);
4592
+ TEST(fd = open("/sys/fs/incremental-fs/instances/1/reads_delayed_min",
4593
+ O_RDONLY | O_CLOEXEC), fd != -1);
4594
+ TESTEQUAL(pread(fd, &c, 1, 0), 1);
4595
+ TESTEQUAL(c, '0');
4596
+ TESTEQUAL(pread(fd, &c, 1, 0), 1);
4597
+ TESTEQUAL(c, '0');
4598
+
4599
+ /* Rename node */
4600
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "sysfs_name=2", true),
4601
+ 0);
4602
+ TESTEQUAL(sysfs_test_directories(false, true), 0);
4603
+ TESTEQUAL(pread(fd, &c, 1, 0), -1);
4604
+
4605
+ /* Try mounting another instance with same node name */
4606
+ TEST(mount_dir2 = concat_file_name(backing_dir, "incfs-mount-dir2"),
4607
+ mount_dir2);
4608
+ rmdir(mount_dir2); /* In case we crashed before */
4609
+ TESTSYSCALL(mkdir(mount_dir2, 0777));
4610
+ TEST(mount_fs_opt(mount_dir2, backing_dir, "sysfs_name=2", false),
4611
+ -1);
4612
+
4613
+ /* Try mounting another instance then remounting with existing name */
4614
+ TESTEQUAL(mount_fs(mount_dir2, backing_dir, 0), 0);
4615
+ TESTEQUAL(mount_fs_opt(mount_dir2, backing_dir, "sysfs_name=2", true),
4616
+ -1);
4617
+
4618
+ /* Remount with no node */
4619
+ TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "", true),
4620
+ 0);
4621
+ TESTEQUAL(sysfs_test_directories(false, false), 0);
4622
+
4623
+ result = TEST_SUCCESS;
4624
+out:
4625
+ umount(mount_dir2);
4626
+ rmdir(mount_dir2);
4627
+ free(mount_dir2);
4628
+ close(fd);
4629
+ umount(mount_dir);
4630
+ free(backing_dir);
26684631 return result;
26694632 }
26704633
....@@ -2691,12 +4654,59 @@
26914654 return mount_dir;
26924655 }
26934656
4657
+int parse_options(int argc, char *const *argv)
4658
+{
4659
+ signed char c;
4660
+
4661
+ while ((c = getopt(argc, argv, "f:t:v")) != -1)
4662
+ switch (c) {
4663
+ case 'f':
4664
+ options.file = strtol(optarg, NULL, 10);
4665
+ break;
4666
+
4667
+ case 't':
4668
+ options.test = strtol(optarg, NULL, 10);
4669
+ break;
4670
+
4671
+ case 'v':
4672
+ options.verbose = true;
4673
+ break;
4674
+
4675
+ default:
4676
+ return -EINVAL;
4677
+ }
4678
+
4679
+ return 0;
4680
+}
4681
+
4682
+struct test_case {
4683
+ int (*pfunc)(const char *dir);
4684
+ const char *name;
4685
+};
4686
+
4687
+void run_one_test(const char *mount_dir, struct test_case *test_case)
4688
+{
4689
+ int ret;
4690
+
4691
+ ksft_print_msg("Running %s\n", test_case->name);
4692
+ ret = test_case->pfunc(mount_dir);
4693
+
4694
+ if (ret == TEST_SUCCESS)
4695
+ ksft_test_result_pass("%s\n", test_case->name);
4696
+ else if (ret == TEST_SKIP)
4697
+ ksft_test_result_skip("%s\n", test_case->name);
4698
+ else
4699
+ ksft_test_result_fail("%s\n", test_case->name);
4700
+}
4701
+
26944702 int main(int argc, char *argv[])
26954703 {
26964704 char *mount_dir = NULL;
2697
- int fails = 0;
26984705 int i;
26994706 int fd, count;
4707
+
4708
+ if (parse_options(argc, argv))
4709
+ ksft_exit_fail_msg("Bad options\n");
27004710
27014711 // Seed randomness pool for testing on QEMU
27024712 // NOTE - this abuses the concept of randomness - do *not* ever do this
....@@ -2721,10 +4731,7 @@
27214731 { \
27224732 test, #test \
27234733 }
2724
- struct {
2725
- int (*pfunc)(char *dir);
2726
- const char *name;
2727
- } cases[] = {
4734
+ struct test_case cases[] = {
27284735 MAKE_TEST(basic_file_ops_test),
27294736 MAKE_TEST(cant_touch_index_test),
27304737 MAKE_TEST(dynamic_files_and_data_test),
....@@ -2737,29 +4744,36 @@
27374744 MAKE_TEST(read_log_test),
27384745 MAKE_TEST(get_blocks_test),
27394746 MAKE_TEST(get_hash_blocks_test),
2740
- MAKE_TEST(large_file),
4747
+ MAKE_TEST(large_file_test),
4748
+ MAKE_TEST(mapped_file_test),
4749
+ MAKE_TEST(compatibility_test),
4750
+ MAKE_TEST(data_block_count_test),
4751
+ MAKE_TEST(hash_block_count_test),
4752
+ MAKE_TEST(per_uid_read_timeouts_test),
4753
+ MAKE_TEST(inotify_test),
4754
+ MAKE_TEST(verity_test),
4755
+ MAKE_TEST(enable_verity_test),
4756
+ MAKE_TEST(mmap_test),
4757
+ MAKE_TEST(truncate_test),
4758
+ MAKE_TEST(stat_test),
4759
+ MAKE_TEST(sysfs_test),
4760
+ MAKE_TEST(sysfs_rename_test),
27414761 };
27424762 #undef MAKE_TEST
27434763
2744
- /* Bring back for kernel 5.x */
2745
- /* ksft_set_plan(ARRAY_SIZE(cases)); */
4764
+ if (options.test) {
4765
+ if (options.test <= 0 || options.test > ARRAY_SIZE(cases))
4766
+ ksft_exit_fail_msg("Invalid test\n");
27464767
2747
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
2748
- ksft_print_msg("Running %s\n", cases[i].name);
2749
- if (cases[i].pfunc(mount_dir) == TEST_SUCCESS)
2750
- ksft_test_result_pass("%s\n", cases[i].name);
2751
- else {
2752
- ksft_test_result_fail("%s\n", cases[i].name);
2753
- fails++;
2754
- }
4768
+ ksft_set_plan(1);
4769
+ run_one_test(mount_dir, &cases[options.test - 1]);
4770
+ } else {
4771
+ ksft_set_plan(ARRAY_SIZE(cases));
4772
+ for (i = 0; i < ARRAY_SIZE(cases); ++i)
4773
+ run_one_test(mount_dir, &cases[i]);
27554774 }
27564775
27574776 umount2(mount_dir, MNT_FORCE);
27584777 rmdir(mount_dir);
2759
-
2760
- if (fails > 0)
2761
- ksft_exit_fail();
2762
- else
2763
- ksft_exit_pass();
2764
- return 0;
4778
+ return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
27654779 }