]> git.saurik.com Git - apple/hfs.git/blob - tests/cases/test-throttled-io.c
hfs-366.50.19.tar.gz
[apple/hfs.git] / tests / cases / test-throttled-io.c
1 #include <sys/fcntl.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/resource.h>
5 #include <CommonCrypto/CommonDigest.h>
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <spawn.h>
9 #include <string.h>
10 #include <signal.h>
11 #include <stdarg.h>
12 #include <sys/errno.h>
13 #include <libkern/OSAtomic.h>
14 #include <zlib.h>
15 #include <pthread.h>
16
17 #include "hfs-tests.h"
18 #include "test-utils.h"
19 #include "disk-image.h"
20
21 TEST(throttled_io)
22
23 static disk_image_t *gDI;
24 static char *gFile1, *gFile2, *gFile3;
25
26 static pid_t gPID = 0;
27 static void *gBuf;
28 static const size_t gBuf_size = 64 * 1024 * 1024;
29
30 static void start_background_io(void)
31 {
32 char *of;
33 asprintf(&of, "of=%s", gFile1);
34
35 assert_no_err(posix_spawn(&gPID, "/bin/dd", NULL, NULL,
36 (char *[]){ "/bin/dd", "if=/dev/random",
37 of, NULL },
38 NULL));
39 }
40
41 static void end_background_io(void)
42 {
43 if ( gPID != 0 )
44 {
45 kill(gPID, SIGKILL);
46 int stat;
47 wait(&stat);
48 gPID = 0;
49 }
50 }
51
52 static int run_test1(void)
53 {
54
55 // Kick off another process to ensure we get throttled
56 start_background_io();
57
58 assert_no_err(setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS,
59 IOPOL_THROTTLE));
60
61 int fd, fd2;
62 assert_with_errno((fd = open("/dev/random", O_RDONLY)) >= 0);
63 assert_with_errno((fd2 = open(gFile2,
64 O_RDWR | O_CREAT | O_TRUNC, 0666)) >= 0);
65
66 assert_no_err(fcntl(fd2, F_SINGLE_WRITER, 1));
67 assert_no_err(fcntl(fd2, F_NOCACHE, 1));
68
69 gBuf = valloc(gBuf_size);
70 CC_SHA1_CTX ctx;
71 CC_SHA1_Init(&ctx);
72
73 ssize_t res = check_io(read(fd, gBuf, gBuf_size), gBuf_size);
74
75 CC_SHA1_Update(&ctx, gBuf, (CC_LONG)res);
76
77 res = check_io(write(fd2, gBuf, res), res);
78
79 bzero(gBuf, gBuf_size);
80
81 CC_SHA1_CTX ctx2;
82 CC_SHA1_Init(&ctx2);
83
84 lseek(fd2, 0, SEEK_SET);
85
86 res = check_io(read(fd2, gBuf, gBuf_size), gBuf_size);
87
88 CC_SHA1_Update(&ctx2, gBuf, (CC_LONG)res);
89
90 uint8_t digest1[CC_SHA1_DIGEST_LENGTH], digest2[CC_SHA1_DIGEST_LENGTH];
91 CC_SHA1_Final(digest1, &ctx);
92 CC_SHA1_Final(digest2, &ctx2);
93
94 assert(!memcmp(digest1, digest2, CC_SHA1_DIGEST_LENGTH));
95
96 assert_no_err (close(fd));
97 assert_no_err (close(fd2));
98
99 end_background_io();
100
101 return 0;
102 }
103
104 static volatile uint64_t written;
105 static volatile bool done;
106
107 static void test2_thread(void)
108 {
109 int fd = open(gFile3, O_RDONLY);
110 assert(fd >= 0);
111
112 void *b = gBuf + gBuf_size / 2;
113 uLong seq = crc32(0, Z_NULL, 0);
114 uint32_t offset = 0;
115
116 do {
117 ssize_t res;
118
119 do {
120 res = check_io(pread(fd, b, gBuf_size / 2, offset), -1);
121 } while (res == 0 && !done);
122
123 assert (res % 4 == 0);
124
125 offset += res;
126
127 for (uLong *p = b; res; ++p, res -= sizeof(uLong)) {
128 seq = crc32(Z_NULL, (void *)&seq, 4);
129 assert(*p == seq);
130 }
131
132 if (offset < written)
133 continue;
134 OSMemoryBarrier();
135 } while (!done);
136
137 assert_no_err (close(fd));
138
139 }
140
141 static int run_test2(void)
142 {
143 start_background_io();
144
145 int fd = open(gFile3, O_RDWR | O_CREAT | O_TRUNC, 0666);
146 assert(fd >= 0);
147
148 assert_no_err(fcntl(fd, F_SINGLE_WRITER, 1));
149 assert_no_err(fcntl(fd, F_NOCACHE, 1));
150
151 pthread_t thread;
152 pthread_create(&thread, NULL, (void *(*)(void *))test2_thread, NULL);
153 uLong seq = crc32(0, Z_NULL, 0);
154
155 for (int i = 0; i < 4; ++i) {
156 uLong *p = gBuf;
157 for (unsigned i = 0; i < gBuf_size / 2 / sizeof(uLong); ++i) {
158 seq = crc32(Z_NULL, (void *)&seq, 4);
159 p[i] = seq;
160 }
161
162 ssize_t res = check_io(write(fd, gBuf, gBuf_size / 2), gBuf_size / 2);
163
164 written += res;
165 }
166
167 OSMemoryBarrier();
168
169 done = true;
170
171 pthread_join(thread, NULL);
172
173 assert_no_err (close(fd));
174
175 end_background_io();
176
177 return 0;
178 }
179
180 static bool clean_up(void)
181 {
182 end_background_io();
183
184 unlink(gFile1);
185 unlink(gFile2);
186 unlink(gFile3);
187
188 free(gFile1);
189 free(gFile2);
190 free(gFile3);
191
192 return true;
193 }
194
195 int run_throttled_io(__unused test_ctx_t *ctx)
196 {
197 gDI = disk_image_get();
198
199 asprintf(&gFile1, "%s/throttled_io.1", gDI->mount_point);
200 asprintf(&gFile2, "%s/throttled_io.2", gDI->mount_point);
201 asprintf(&gFile3, "%s/throttled_io.3", gDI->mount_point);
202
203 test_cleanup(^ bool {
204 return clean_up();
205 });
206
207 int res = run_test1();
208 if (res)
209 return res;
210
211 res = run_test2();
212 if (res)
213 return res;
214
215 return res;
216 }