1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Linaro Limited. All rights reserved.
4 * Author: Sumit Garg <sumit.garg@linaro.org>
5 */
6
7 /*
8 * sync_file_range02
9 *
10 * It basically tests sync_file_range() to sync test file range having large
11 * dirty file pages to block device. Also, it tests all supported filesystems
12 * on a test block device.
13 */
14
15 #define _GNU_SOURCE
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include "tst_test.h"
21 #include "lapi/sync_file_range.h"
22 #include "check_sync_file_range.h"
23
24 #define MNTPOINT "mnt_point"
25 #define FNAME1 MNTPOINT"/test1"
26 #define FNAME2 MNTPOINT"/test2"
27 #define FNAME3 MNTPOINT"/test3"
28 #define FILE_SZ_MB 32
29 #define FILE_SZ (FILE_SZ_MB * TST_MB)
30 #define MODE 0644
31
32 struct testcase {
33 char *fname;
34 off64_t sync_off;
35 off64_t sync_size;
36 size_t exp_sync_size;
37 off64_t write_off;
38 size_t write_size_mb;
39 const char *desc;
40 };
41
verify_sync_file_range(struct testcase * tc)42 static void verify_sync_file_range(struct testcase *tc)
43 {
44 int fd;
45 unsigned long written;
46
47 fd = SAFE_OPEN(tc->fname, O_RDWR|O_CREAT, MODE);
48
49 lseek(fd, tc->write_off, SEEK_SET);
50
51 tst_dev_sync(fd);
52 tst_dev_bytes_written(tst_device->dev);
53
54 tst_fill_fd(fd, 0, TST_MB, tc->write_size_mb);
55
56 TEST(sync_file_range(fd, tc->sync_off, tc->sync_size,
57 SYNC_FILE_RANGE_WAIT_BEFORE |
58 SYNC_FILE_RANGE_WRITE |
59 SYNC_FILE_RANGE_WAIT_AFTER));
60
61 if (TST_RET)
62 tst_brk(TFAIL | TTERRNO, "sync_file_range() failed");
63
64 written = tst_dev_bytes_written(tst_device->dev);
65
66 fsync(fd);
67
68 SAFE_CLOSE(fd);
69
70 if (written >= tc->exp_sync_size)
71 tst_res(TPASS, "%s", tc->desc);
72 else
73 tst_res(TFAIL, "%s: Synced %li, expected %li", tc->desc,
74 written, tc->exp_sync_size);
75 }
76
77 static struct testcase testcases[] = {
78 {FNAME1,
79 0, FILE_SZ,
80 FILE_SZ,
81 0, FILE_SZ_MB,
82 "Sync equals write"},
83 {FNAME2,
84 FILE_SZ/4, FILE_SZ/2,
85 FILE_SZ/2,
86 0, FILE_SZ_MB,
87 "Sync inside of write"},
88 {FNAME3,
89 FILE_SZ/4, FILE_SZ/2,
90 FILE_SZ/4,
91 FILE_SZ/2, FILE_SZ_MB/4,
92 "Sync overlaps with write"},
93 };
94
run(unsigned int i)95 static void run(unsigned int i)
96 {
97 verify_sync_file_range(&testcases[i]);
98 }
99
setup(void)100 static void setup(void)
101 {
102 if (!check_sync_file_range())
103 tst_brk(TCONF, "sync_file_range() not supported");
104
105 /*
106 * Fat does not support sparse files, we have to pre-fill the file so
107 * that the zero-filled start of the file has been written to disk
108 * before the test starts.
109 */
110 if (!strcmp(tst_device->fs_type, "vfat")) {
111 tst_res(TINFO, "Pre-filling file");
112 tst_fill_file(FNAME3, 0, TST_MB, FILE_SZ_MB);
113 int fd = SAFE_OPEN(FNAME3, O_RDONLY);
114 fsync(fd);
115 SAFE_CLOSE(fd);
116 }
117 }
118
119 static struct tst_test test = {
120 .tcnt = ARRAY_SIZE(testcases),
121 .needs_root = 1,
122 .mount_device = 1,
123 .all_filesystems = 1,
124 .dev_fs_flags = TST_FS_SKIP_FUSE,
125 .mntpoint = MNTPOINT,
126 .setup = setup,
127 .test = run,
128 };
129