]> git.saurik.com Git - apple/hfs.git/blame_incremental - tests/cases/test-throttled-io.c
hfs-366.70.1.tar.gz
[apple/hfs.git] / tests / cases / test-throttled-io.c
... / ...
CommitLineData
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
21TEST(throttled_io)
22
23static disk_image_t *gDI;
24static char *gFile1, *gFile2, *gFile3;
25
26static pid_t gPID = 0;
27static void *gBuf;
28static const size_t gBuf_size = 64 * 1024 * 1024;
29
30static 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
41static 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
52static 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
104static volatile uint64_t written;
105static volatile bool done;
106
107static 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
141static 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
180static 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
195int 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}