xref: /xnu-12377.41.6/tests/disk_mount_conditioner.m (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions#ifdef T_NAMESPACE
2*bbb1b6f9SApple OSS Distributions#undef T_NAMESPACE
3*bbb1b6f9SApple OSS Distributions#endif
4*bbb1b6f9SApple OSS Distributions#include <darwintest.h>
5*bbb1b6f9SApple OSS Distributions#include <darwintest_utils.h>
6*bbb1b6f9SApple OSS Distributions
7*bbb1b6f9SApple OSS Distributions#include <stdlib.h>
8*bbb1b6f9SApple OSS Distributions#include <unistd.h>
9*bbb1b6f9SApple OSS Distributions#include <fcntl.h>
10*bbb1b6f9SApple OSS Distributions#include <System/sys/fsctl.h>
11*bbb1b6f9SApple OSS Distributions#include <paths.h>
12*bbb1b6f9SApple OSS Distributions#import <Foundation/Foundation.h>
13*bbb1b6f9SApple OSS Distributions
14*bbb1b6f9SApple OSS Distributionsstatic char *mktempdir(void);
15*bbb1b6f9SApple OSS Distributionsstatic char *mktempmount(void);
16*bbb1b6f9SApple OSS Distributions
17*bbb1b6f9SApple OSS Distributions#ifndef TEST_UNENTITLED
18*bbb1b6f9SApple OSS Distributionsstatic int system_legal(const char *command);
19*bbb1b6f9SApple OSS Distributionsstatic char *mkramdisk(void);
20*bbb1b6f9SApple OSS Distributionsstatic uint64_t time_for_read(int fd, const char *expected);
21*bbb1b6f9SApple OSS Distributionsstatic void perf_setup(char **path, int *fd);
22*bbb1b6f9SApple OSS Distributions
23*bbb1b6f9SApple OSS Distributions#define READSIZE 1024L
24*bbb1b6f9SApple OSS Distributions#endif /* !TEST_UNENTITLED */
25*bbb1b6f9SApple OSS Distributions
26*bbb1b6f9SApple OSS DistributionsT_GLOBAL_META(
27*bbb1b6f9SApple OSS Distributions	T_META_NAMESPACE("xnu.vfs.dmc"),
28*bbb1b6f9SApple OSS Distributions	T_META_ASROOT(true),
29*bbb1b6f9SApple OSS Distributions	T_META_RUN_CONCURRENTLY(true)
30*bbb1b6f9SApple OSS Distributions	);
31*bbb1b6f9SApple OSS Distributions
32*bbb1b6f9SApple OSS Distributions#pragma mark Entitled Tests
33*bbb1b6f9SApple OSS Distributions
34*bbb1b6f9SApple OSS Distributions#ifndef TEST_UNENTITLED
35*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_get_uninitialized,
36*bbb1b6f9SApple OSS Distributions    "Initial fsctl.get should return zeros",
37*bbb1b6f9SApple OSS Distributions    T_META_ASROOT(false), T_META_TAG_VM_PREFERRED)
38*bbb1b6f9SApple OSS Distributions{
39*bbb1b6f9SApple OSS Distributions	int err;
40*bbb1b6f9SApple OSS Distributions	char *mount_path;
41*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info = {0};
42*bbb1b6f9SApple OSS Distributions	disk_conditioner_info expected_info = {0};
43*bbb1b6f9SApple OSS Distributions
44*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
45*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
46*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
47*bbb1b6f9SApple OSS Distributions
48*bbb1b6f9SApple OSS Distributions	info.enabled = true;
49*bbb1b6f9SApple OSS Distributions	info.is_ssd = true;
50*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
51*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
52*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_GET)");
53*bbb1b6f9SApple OSS Distributions
54*bbb1b6f9SApple OSS Distributions	err = memcmp(&info, &expected_info, sizeof(info));
55*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "initial DMC info is zeroed");
56*bbb1b6f9SApple OSS Distributions}
57*bbb1b6f9SApple OSS Distributions
58*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_set,
59*bbb1b6f9SApple OSS Distributions    "fsctl.set should succeed and fsctl.get should verify", T_META_TAG_VM_PREFERRED)
60*bbb1b6f9SApple OSS Distributions{
61*bbb1b6f9SApple OSS Distributions	int err;
62*bbb1b6f9SApple OSS Distributions	char *mount_path;
63*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info = {0};
64*bbb1b6f9SApple OSS Distributions	disk_conditioner_info expected_info = {0};
65*bbb1b6f9SApple OSS Distributions
66*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
67*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
68*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
69*bbb1b6f9SApple OSS Distributions
70*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
71*bbb1b6f9SApple OSS Distributions	info.access_time_usec = 10;
72*bbb1b6f9SApple OSS Distributions	info.read_throughput_mbps = 40;
73*bbb1b6f9SApple OSS Distributions	info.write_throughput_mbps = 40;
74*bbb1b6f9SApple OSS Distributions	info.is_ssd = 0;
75*bbb1b6f9SApple OSS Distributions	info.ioqueue_depth = 8;
76*bbb1b6f9SApple OSS Distributions	info.maxreadcnt = 8;
77*bbb1b6f9SApple OSS Distributions	info.maxwritecnt = 8;
78*bbb1b6f9SApple OSS Distributions	info.segreadcnt = 8;
79*bbb1b6f9SApple OSS Distributions	info.segwritecnt = 8;
80*bbb1b6f9SApple OSS Distributions	expected_info = info;
81*bbb1b6f9SApple OSS Distributions
82*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, &info, 0);
83*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
84*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET)");
85*bbb1b6f9SApple OSS Distributions
86*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
87*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
88*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_GET) after SET");
89*bbb1b6f9SApple OSS Distributions
90*bbb1b6f9SApple OSS Distributions	err = memcmp(&info, &expected_info, sizeof(info));
91*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.get is the info configured by fsctl.set");
92*bbb1b6f9SApple OSS Distributions}
93*bbb1b6f9SApple OSS Distributions
94*bbb1b6f9SApple OSS Distributionsstatic void
95*bbb1b6f9SApple OSS Distributionsverify_mount_fallback_values(const char *mount_path, disk_conditioner_info *info)
96*bbb1b6f9SApple OSS Distributions{
97*bbb1b6f9SApple OSS Distributions	int err;
98*bbb1b6f9SApple OSS Distributions	disk_conditioner_info newinfo = {0};
99*bbb1b6f9SApple OSS Distributions
100*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, info, 0);
101*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
102*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET)");
103*bbb1b6f9SApple OSS Distributions
104*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &newinfo, 0);
105*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
106*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_GET) after SET");
107*bbb1b6f9SApple OSS Distributions
108*bbb1b6f9SApple OSS Distributions	// without querying the drive for the expected values, the best we can do is
109*bbb1b6f9SApple OSS Distributions	// assert that they are not zero (impossible) or less than UINT32_MAX (unlikely)
110*bbb1b6f9SApple OSS Distributions	T_ASSERT_GT(newinfo.ioqueue_depth, 0u, "ioqueue_depth is the value from the mount");
111*bbb1b6f9SApple OSS Distributions	T_ASSERT_GT(newinfo.maxreadcnt, 0u, "maxreadcnt is value from the mount");
112*bbb1b6f9SApple OSS Distributions	T_ASSERT_GT(newinfo.maxwritecnt, 0u, "maxwritecnt is value from the mount");
113*bbb1b6f9SApple OSS Distributions	T_ASSERT_GT(newinfo.segreadcnt, 0u, "segreadcnt is value from the mount");
114*bbb1b6f9SApple OSS Distributions	T_ASSERT_GT(newinfo.segwritecnt, 0u, "segwritecnt is value from the mount");
115*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT(newinfo.ioqueue_depth, UINT32_MAX, "ioqueue_depth is the value from the mount");
116*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT(newinfo.maxreadcnt, UINT32_MAX, "maxreadcnt is value from the mount");
117*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT(newinfo.maxwritecnt, UINT32_MAX, "maxwritecnt is value from the mount");
118*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT(newinfo.segreadcnt, UINT32_MAX, "segreadcnt is value from the mount");
119*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT(newinfo.segwritecnt, UINT32_MAX, "segwritecnt is value from the mount");
120*bbb1b6f9SApple OSS Distributions}
121*bbb1b6f9SApple OSS Distributions
122*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_set_zero,
123*bbb1b6f9SApple OSS Distributions    "fsctl.set zero values should fall back to original mount settings", T_META_TAG_VM_PREFERRED)
124*bbb1b6f9SApple OSS Distributions{
125*bbb1b6f9SApple OSS Distributions	char *mount_path;
126*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info = {0};
127*bbb1b6f9SApple OSS Distributions
128*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
129*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
130*bbb1b6f9SApple OSS Distributions
131*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
132*bbb1b6f9SApple OSS Distributions	/* everything else is 0 */
133*bbb1b6f9SApple OSS Distributions
134*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
135*bbb1b6f9SApple OSS Distributions
136*bbb1b6f9SApple OSS Distributions	verify_mount_fallback_values(mount_path, &info);
137*bbb1b6f9SApple OSS Distributions}
138*bbb1b6f9SApple OSS Distributions
139*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_set_out_of_bounds,
140*bbb1b6f9SApple OSS Distributions    "fsctl.set out-of-bounds values should fall back to original mount settings", T_META_TAG_VM_PREFERRED)
141*bbb1b6f9SApple OSS Distributions{
142*bbb1b6f9SApple OSS Distributions	char *mount_path;
143*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info;
144*bbb1b6f9SApple OSS Distributions
145*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
146*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
147*bbb1b6f9SApple OSS Distributions
148*bbb1b6f9SApple OSS Distributions	memset(&info, UINT32_MAX, sizeof(info));
149*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
150*bbb1b6f9SApple OSS Distributions	info.access_time_usec = 0;
151*bbb1b6f9SApple OSS Distributions	info.read_throughput_mbps = 0;
152*bbb1b6f9SApple OSS Distributions	info.write_throughput_mbps = 0;
153*bbb1b6f9SApple OSS Distributions	/* everything else is UINT32_MAX */
154*bbb1b6f9SApple OSS Distributions
155*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
156*bbb1b6f9SApple OSS Distributions
157*bbb1b6f9SApple OSS Distributions	verify_mount_fallback_values(mount_path, &info);
158*bbb1b6f9SApple OSS Distributions}
159*bbb1b6f9SApple OSS Distributions
160*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_restore_mount_fields,
161*bbb1b6f9SApple OSS Distributions    "fsctl.set should restore fields on mount_t that it temporarily overrides", T_META_TAG_VM_PREFERRED)
162*bbb1b6f9SApple OSS Distributions{
163*bbb1b6f9SApple OSS Distributions	int err;
164*bbb1b6f9SApple OSS Distributions	char *mount_path;
165*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info;
166*bbb1b6f9SApple OSS Distributions	disk_conditioner_info mount_fields;
167*bbb1b6f9SApple OSS Distributions
168*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
169*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
170*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
171*bbb1b6f9SApple OSS Distributions
172*bbb1b6f9SApple OSS Distributions	/* first set out-of-bounds values to retrieve the original mount_t fields */
173*bbb1b6f9SApple OSS Distributions	memset(&info, UINT32_MAX, sizeof(info));
174*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
175*bbb1b6f9SApple OSS Distributions	info.access_time_usec = 0;
176*bbb1b6f9SApple OSS Distributions	info.read_throughput_mbps = 0;
177*bbb1b6f9SApple OSS Distributions	info.write_throughput_mbps = 0;
178*bbb1b6f9SApple OSS Distributions	/* everything else is UINT32_MAX */
179*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, &info, 0);
180*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
181*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET)");
182*bbb1b6f9SApple OSS Distributions
183*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &mount_fields, 0);
184*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
185*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_GET)");
186*bbb1b6f9SApple OSS Distributions
187*bbb1b6f9SApple OSS Distributions	/* now turn off the disk conditioner which should restore fields on the mount_t */
188*bbb1b6f9SApple OSS Distributions	memset(&info, 1, sizeof(info));
189*bbb1b6f9SApple OSS Distributions	info.enabled = 0;
190*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, &info, 0);
191*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
192*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET)");
193*bbb1b6f9SApple OSS Distributions
194*bbb1b6f9SApple OSS Distributions	/* and finally set out-of-bounds values again to retrieve the new mount_t fields which should not have changed */
195*bbb1b6f9SApple OSS Distributions	memset(&info, UINT32_MAX, sizeof(info));
196*bbb1b6f9SApple OSS Distributions	info.enabled = 0;
197*bbb1b6f9SApple OSS Distributions	info.access_time_usec = 0;
198*bbb1b6f9SApple OSS Distributions	info.read_throughput_mbps = 0;
199*bbb1b6f9SApple OSS Distributions	info.write_throughput_mbps = 0;
200*bbb1b6f9SApple OSS Distributions	/* everything else is UINT32_MAX */
201*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, &info, 0);
202*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
203*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET)");
204*bbb1b6f9SApple OSS Distributions
205*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
206*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
207*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_GET)");
208*bbb1b6f9SApple OSS Distributions
209*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ(info.maxreadcnt, mount_fields.maxreadcnt, "mount_t maxreadcnt restored");
210*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ(info.maxwritecnt, mount_fields.maxwritecnt, "mount_t maxwritecnt restored");
211*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ(info.segreadcnt, mount_fields.segreadcnt, "mount_t segreadcnt restored");
212*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ(info.segwritecnt, mount_fields.segwritecnt, "mount_t segwritecnt restored");
213*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ(info.ioqueue_depth, mount_fields.ioqueue_depth, "mount_t ioqueue_depth restored");
214*bbb1b6f9SApple OSS Distributions}
215*bbb1b6f9SApple OSS Distributions
216*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_get_nonroot,
217*bbb1b6f9SApple OSS Distributions    "fsctl.get should not require root",
218*bbb1b6f9SApple OSS Distributions    T_META_ASROOT(false), T_META_TAG_VM_PREFERRED)
219*bbb1b6f9SApple OSS Distributions{
220*bbb1b6f9SApple OSS Distributions	int err;
221*bbb1b6f9SApple OSS Distributions	char *mount_path;
222*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info;
223*bbb1b6f9SApple OSS Distributions
224*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
225*bbb1b6f9SApple OSS Distributions	// make sure we're not root
226*bbb1b6f9SApple OSS Distributions	if (0 == geteuid()) {
227*bbb1b6f9SApple OSS Distributions		seteuid(5000);
228*bbb1b6f9SApple OSS Distributions	}
229*bbb1b6f9SApple OSS Distributions
230*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
231*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
232*bbb1b6f9SApple OSS Distributions
233*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
234*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
235*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.get without root");
236*bbb1b6f9SApple OSS Distributions}
237*bbb1b6f9SApple OSS Distributions
238*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_set_nonroot,
239*bbb1b6f9SApple OSS Distributions    "fsctl.set should require root",
240*bbb1b6f9SApple OSS Distributions    T_META_ASROOT(false), T_META_TAG_VM_PREFERRED)
241*bbb1b6f9SApple OSS Distributions{
242*bbb1b6f9SApple OSS Distributions	int err;
243*bbb1b6f9SApple OSS Distributions	char *mount_path;
244*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info = {0};
245*bbb1b6f9SApple OSS Distributions	disk_conditioner_info expected_info = {0};
246*bbb1b6f9SApple OSS Distributions
247*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
248*bbb1b6f9SApple OSS Distributions	// make sure we're not root
249*bbb1b6f9SApple OSS Distributions	if (0 == geteuid()) {
250*bbb1b6f9SApple OSS Distributions		seteuid(5000);
251*bbb1b6f9SApple OSS Distributions	}
252*bbb1b6f9SApple OSS Distributions
253*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
254*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
255*bbb1b6f9SApple OSS Distributions
256*bbb1b6f9SApple OSS Distributions	// save original info
257*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &expected_info, 0);
258*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
259*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "Get original DMC info");
260*bbb1b6f9SApple OSS Distributions
261*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
262*bbb1b6f9SApple OSS Distributions	info.access_time_usec = 10;
263*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, &info, 0);
264*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
265*bbb1b6f9SApple OSS Distributions	T_ASSERT_NE_INT(0, err, "fsctl.set returns error without root");
266*bbb1b6f9SApple OSS Distributions
267*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
268*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
269*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.get after nonroot fsctl.set");
270*bbb1b6f9SApple OSS Distributions
271*bbb1b6f9SApple OSS Distributions	err = memcmp(&info, &expected_info, sizeof(info));
272*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.set should not change info without root");
273*bbb1b6f9SApple OSS Distributions}
274*bbb1b6f9SApple OSS Distributions
275*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_delays,
276*bbb1b6f9SApple OSS Distributions    "Validate I/O delays when DMC is enabled",
277*bbb1b6f9SApple OSS Distributions    T_META_ENABLED(!TARGET_OS_BRIDGE), // diskutil is unavailable on bridgeOS
278*bbb1b6f9SApple OSS Distributions    T_META_RUN_CONCURRENTLY(false), T_META_TAG_VM_PREFERRED)
279*bbb1b6f9SApple OSS Distributions{
280*bbb1b6f9SApple OSS Distributions	char *path;
281*bbb1b6f9SApple OSS Distributions	int fd;
282*bbb1b6f9SApple OSS Distributions	int err;
283*bbb1b6f9SApple OSS Distributions	uint64_t elapsed_nsec, expected_nsec;
284*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info = {0};
285*bbb1b6f9SApple OSS Distributions	char buf[READSIZE];
286*bbb1b6f9SApple OSS Distributions
287*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
288*bbb1b6f9SApple OSS Distributions	perf_setup(&path, &fd);
289*bbb1b6f9SApple OSS Distributions	memset(buf, 0xFF, sizeof(buf));
290*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_LONG((long)sizeof(buf), write(fd, buf, sizeof(buf)), "write random data to temp file");
291*bbb1b6f9SApple OSS Distributions	fcntl(fd, F_FULLFSYNC);
292*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
293*bbb1b6f9SApple OSS Distributions
294*bbb1b6f9SApple OSS Distributions	expected_nsec = NSEC_PER_SEC / 2;
295*bbb1b6f9SApple OSS Distributions
296*bbb1b6f9SApple OSS Distributions	// measure delay before setting parameters (should be none)
297*bbb1b6f9SApple OSS Distributions	elapsed_nsec = time_for_read(fd, buf);
298*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT_ULLONG(elapsed_nsec, expected_nsec, "DMC disabled read(%ld) is reasonably fast", READSIZE);
299*bbb1b6f9SApple OSS Distributions
300*bbb1b6f9SApple OSS Distributions	// measure delay after setting parameters
301*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
302*bbb1b6f9SApple OSS Distributions	info.access_time_usec = expected_nsec / NSEC_PER_USEC;
303*bbb1b6f9SApple OSS Distributions	info.read_throughput_mbps = 40;
304*bbb1b6f9SApple OSS Distributions	info.write_throughput_mbps = 40;
305*bbb1b6f9SApple OSS Distributions	info.is_ssd = 1; // is_ssd will ensure we get constant access_time delays rather than scaled
306*bbb1b6f9SApple OSS Distributions	err = fsctl(path, DISK_CONDITIONER_IOC_SET, &info, 0);
307*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
308*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET) delay");
309*bbb1b6f9SApple OSS Distributions
310*bbb1b6f9SApple OSS Distributions	elapsed_nsec = time_for_read(fd, buf);
311*bbb1b6f9SApple OSS Distributions	T_ASSERT_GT_ULLONG(elapsed_nsec, expected_nsec, "DMC enabled read(%ld) is at least the expected delay", READSIZE);
312*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT_ULLONG(elapsed_nsec, 2 * expected_nsec, "DMC enabled read(%ld) is no more than twice the expected delay", READSIZE);
313*bbb1b6f9SApple OSS Distributions
314*bbb1b6f9SApple OSS Distributions	// measure delay after resetting parameters (should be none)
315*bbb1b6f9SApple OSS Distributions	info.enabled = 0;
316*bbb1b6f9SApple OSS Distributions	err = fsctl(path, DISK_CONDITIONER_IOC_SET, &info, 0);
317*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
318*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl(DISK_CONDITIONER_IOC_SET) reset delay");
319*bbb1b6f9SApple OSS Distributions
320*bbb1b6f9SApple OSS Distributions	usleep(USEC_PER_SEC / 2); // might still be other I/O inflight
321*bbb1b6f9SApple OSS Distributions	elapsed_nsec = time_for_read(fd, buf);
322*bbb1b6f9SApple OSS Distributions	T_ASSERT_LT_ULLONG(elapsed_nsec, expected_nsec, "After disabling DMC read(%ld) is reasonably fast", READSIZE);
323*bbb1b6f9SApple OSS Distributions}
324*bbb1b6f9SApple OSS Distributions
325*bbb1b6f9SApple OSS Distributions#else /* TEST_UNENTITLED */
326*bbb1b6f9SApple OSS Distributions
327*bbb1b6f9SApple OSS Distributions#pragma mark Unentitled Tests
328*bbb1b6f9SApple OSS Distributions
329*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_get_unentitled,
330*bbb1b6f9SApple OSS Distributions    "fsctl.get should not require entitlement", T_META_TAG_VM_PREFERRED)
331*bbb1b6f9SApple OSS Distributions{
332*bbb1b6f9SApple OSS Distributions	int err;
333*bbb1b6f9SApple OSS Distributions	char *mount_path;
334*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info;
335*bbb1b6f9SApple OSS Distributions
336*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
337*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
338*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
339*bbb1b6f9SApple OSS Distributions
340*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
341*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
342*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.get without entitlement");
343*bbb1b6f9SApple OSS Distributions}
344*bbb1b6f9SApple OSS Distributions
345*bbb1b6f9SApple OSS DistributionsT_DECL(fsctl_set_unentitled,
346*bbb1b6f9SApple OSS Distributions    "fsctl.set should require entitlement", T_META_TAG_VM_PREFERRED)
347*bbb1b6f9SApple OSS Distributions{
348*bbb1b6f9SApple OSS Distributions	int err;
349*bbb1b6f9SApple OSS Distributions	char *mount_path;
350*bbb1b6f9SApple OSS Distributions	disk_conditioner_info info = {0};
351*bbb1b6f9SApple OSS Distributions	disk_conditioner_info expected_info = {0};
352*bbb1b6f9SApple OSS Distributions
353*bbb1b6f9SApple OSS Distributions	T_SETUPBEGIN;
354*bbb1b6f9SApple OSS Distributions	mount_path = mktempmount();
355*bbb1b6f9SApple OSS Distributions	T_SETUPEND;
356*bbb1b6f9SApple OSS Distributions
357*bbb1b6f9SApple OSS Distributions	// save original info
358*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &expected_info, 0);
359*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
360*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "Get original DMC info");
361*bbb1b6f9SApple OSS Distributions
362*bbb1b6f9SApple OSS Distributions	info.enabled = 1;
363*bbb1b6f9SApple OSS Distributions	info.access_time_usec = 10;
364*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_SET, &info, 0);
365*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
366*bbb1b6f9SApple OSS Distributions	T_ASSERT_NE_INT(0, err, "fsctl.set returns error without entitlement");
367*bbb1b6f9SApple OSS Distributions
368*bbb1b6f9SApple OSS Distributions	err = fsctl(mount_path, DISK_CONDITIONER_IOC_GET, &info, 0);
369*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
370*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.get after unentitled fsctl.set");
371*bbb1b6f9SApple OSS Distributions
372*bbb1b6f9SApple OSS Distributions	err = memcmp(&info, &expected_info, sizeof(info));
373*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, err, "fsctl.set should not change info without entitlement");
374*bbb1b6f9SApple OSS Distributions}
375*bbb1b6f9SApple OSS Distributions
376*bbb1b6f9SApple OSS Distributions#endif /* TEST_UNENTITLED */
377*bbb1b6f9SApple OSS Distributions
378*bbb1b6f9SApple OSS Distributions#pragma mark Helpers
379*bbb1b6f9SApple OSS Distributions
380*bbb1b6f9SApple OSS Distributionsstatic char *
381*bbb1b6f9SApple OSS Distributionsmktempdir(void)
382*bbb1b6f9SApple OSS Distributions{
383*bbb1b6f9SApple OSS Distributions	char *path = malloc(PATH_MAX);
384*bbb1b6f9SApple OSS Distributions	strcpy(path, "/tmp/dmc.XXXXXXXX");
385*bbb1b6f9SApple OSS Distributions	atexit_b(^{ free(path); });
386*bbb1b6f9SApple OSS Distributions
387*bbb1b6f9SApple OSS Distributions	// create a temporary mount to run the fsctl on
388*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
389*bbb1b6f9SApple OSS Distributions	T_ASSERT_NOTNULL(mkdtemp(path), "Create temporary directory");
390*bbb1b6f9SApple OSS Distributions	atexit_b(^{ remove(path); });
391*bbb1b6f9SApple OSS Distributions
392*bbb1b6f9SApple OSS Distributions	return path;
393*bbb1b6f9SApple OSS Distributions}
394*bbb1b6f9SApple OSS Distributions
395*bbb1b6f9SApple OSS Distributions/*
396*bbb1b6f9SApple OSS Distributions * Return the path to a temporary mount
397*bbb1b6f9SApple OSS Distributions * with no usable filesystem but still
398*bbb1b6f9SApple OSS Distributions * can be configured by the disk conditioner
399*bbb1b6f9SApple OSS Distributions *
400*bbb1b6f9SApple OSS Distributions * Faster than creating a ram disk to test with
401*bbb1b6f9SApple OSS Distributions * when access to the filesystem is not necessary
402*bbb1b6f9SApple OSS Distributions */
403*bbb1b6f9SApple OSS Distributionsstatic char *
404*bbb1b6f9SApple OSS Distributionsmktempmount(void)
405*bbb1b6f9SApple OSS Distributions{
406*bbb1b6f9SApple OSS Distributions	char *mount_path = mktempdir();
407*bbb1b6f9SApple OSS Distributions
408*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
409*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, mount("devfs", mount_path, MNT_RDONLY, NULL), "Create temporary devfs mount");
410*bbb1b6f9SApple OSS Distributions	atexit_b(^{ unmount(mount_path, MNT_FORCE); });
411*bbb1b6f9SApple OSS Distributions
412*bbb1b6f9SApple OSS Distributions	return mount_path;
413*bbb1b6f9SApple OSS Distributions}
414*bbb1b6f9SApple OSS Distributions
415*bbb1b6f9SApple OSS Distributions#ifndef TEST_UNENTITLED
416*bbb1b6f9SApple OSS Distributions
417*bbb1b6f9SApple OSS Distributions/*
418*bbb1b6f9SApple OSS Distributions * Wrapper around dt_launch_tool/dt_waitpid
419*bbb1b6f9SApple OSS Distributions * that works like libc:system()
420*bbb1b6f9SApple OSS Distributions */
421*bbb1b6f9SApple OSS Distributionsstatic int
422*bbb1b6f9SApple OSS Distributionssystem_legal(const char *command)
423*bbb1b6f9SApple OSS Distributions{
424*bbb1b6f9SApple OSS Distributions	pid_t pid = -1;
425*bbb1b6f9SApple OSS Distributions	int exit_status = 0;
426*bbb1b6f9SApple OSS Distributions	const char *argv[] = {
427*bbb1b6f9SApple OSS Distributions		_PATH_BSHELL,
428*bbb1b6f9SApple OSS Distributions		"-c",
429*bbb1b6f9SApple OSS Distributions		command,
430*bbb1b6f9SApple OSS Distributions		NULL
431*bbb1b6f9SApple OSS Distributions	};
432*bbb1b6f9SApple OSS Distributions
433*bbb1b6f9SApple OSS Distributions	int rc = dt_launch_tool(&pid, (char **)(void *)argv, false, NULL, NULL);
434*bbb1b6f9SApple OSS Distributions	if (rc != 0) {
435*bbb1b6f9SApple OSS Distributions		return -1;
436*bbb1b6f9SApple OSS Distributions	}
437*bbb1b6f9SApple OSS Distributions	if (!dt_waitpid(pid, &exit_status, NULL, 30)) {
438*bbb1b6f9SApple OSS Distributions		if (exit_status != 0) {
439*bbb1b6f9SApple OSS Distributions			return exit_status;
440*bbb1b6f9SApple OSS Distributions		}
441*bbb1b6f9SApple OSS Distributions		return -1;
442*bbb1b6f9SApple OSS Distributions	}
443*bbb1b6f9SApple OSS Distributions
444*bbb1b6f9SApple OSS Distributions	return exit_status;
445*bbb1b6f9SApple OSS Distributions}
446*bbb1b6f9SApple OSS Distributions
447*bbb1b6f9SApple OSS Distributions/*
448*bbb1b6f9SApple OSS Distributions * Return the path to a temporary mount
449*bbb1b6f9SApple OSS Distributions * that contains a usable APFS filesystem
450*bbb1b6f9SApple OSS Distributions * mounted via a ram disk
451*bbb1b6f9SApple OSS Distributions */
452*bbb1b6f9SApple OSS Distributionsstatic char *
453*bbb1b6f9SApple OSS Distributionsmkramdisk(void)
454*bbb1b6f9SApple OSS Distributions{
455*bbb1b6f9SApple OSS Distributions	char cmd[1024];
456*bbb1b6f9SApple OSS Distributions	char *dev_disk_file = malloc(256);
457*bbb1b6f9SApple OSS Distributions	atexit_b(^{ free(dev_disk_file); });
458*bbb1b6f9SApple OSS Distributions	strcpy(dev_disk_file, "/tmp/dmc.ramdisk.XXXXXXXX");
459*bbb1b6f9SApple OSS Distributions
460*bbb1b6f9SApple OSS Distributions	T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(mktemp(dev_disk_file), "Create temporary file to store dev disk for ramdisk");
461*bbb1b6f9SApple OSS Distributions	atexit_b(^{ remove(dev_disk_file); });
462*bbb1b6f9SApple OSS Distributions
463*bbb1b6f9SApple OSS Distributions	// create the RAM disk device
464*bbb1b6f9SApple OSS Distributions	// dev_disk_file will store the /dev/diskX path
465*bbb1b6f9SApple OSS Distributions	snprintf(cmd, sizeof(cmd), "diskimagetool attach --nomount ram://16m > %s", dev_disk_file);
466*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, system_legal(cmd), "Create ramdisk");
467*bbb1b6f9SApple OSS Distributions
468*bbb1b6f9SApple OSS Distributions	atexit_b(^{
469*bbb1b6f9SApple OSS Distributions		char eject_cmd[1024];
470*bbb1b6f9SApple OSS Distributions		snprintf(eject_cmd, sizeof(eject_cmd), "diskutil eject force `cat %s`", dev_disk_file);
471*bbb1b6f9SApple OSS Distributions		system_legal(eject_cmd);
472*bbb1b6f9SApple OSS Distributions		remove(dev_disk_file);
473*bbb1b6f9SApple OSS Distributions	});
474*bbb1b6f9SApple OSS Distributions
475*bbb1b6f9SApple OSS Distributions	// initialize and mount as an APFS volume
476*bbb1b6f9SApple OSS Distributions	snprintf(cmd, sizeof(cmd), "diskutil eraseVolume APFS dmc.ramdisk `cat %s`", dev_disk_file);
477*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, system_legal(cmd), "Initialize ramdisk as APFS");
478*bbb1b6f9SApple OSS Distributions
479*bbb1b6f9SApple OSS Distributions	// on iOS the previous eraseVolume doesn't automatically mount
480*bbb1b6f9SApple OSS Distributions	// on macOS this mount will be redundant, but successful
481*bbb1b6f9SApple OSS Distributions	snprintf(cmd, sizeof(cmd), "diskutil mountDisk `cat %s`", dev_disk_file);
482*bbb1b6f9SApple OSS Distributions	T_ASSERT_EQ_INT(0, system_legal(cmd), "Mount ramdisk");
483*bbb1b6f9SApple OSS Distributions
484*bbb1b6f9SApple OSS Distributions	// on iOS the previous mountDisk doesn't support -mountPoint, so we have to find where it was mounted
485*bbb1b6f9SApple OSS Distributions	char *mount_info_path = malloc(256);
486*bbb1b6f9SApple OSS Distributions	strcpy(mount_info_path, "/tmp/dmc.mount_info.XXXXXXXX");
487*bbb1b6f9SApple OSS Distributions	T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(mktemp(mount_info_path), "Create temporary file to store mount info for ramdisk");
488*bbb1b6f9SApple OSS Distributions	atexit_b(^{ remove(mount_info_path); });
489*bbb1b6f9SApple OSS Distributions
490*bbb1b6f9SApple OSS Distributions	snprintf(cmd, sizeof(cmd), "diskimagetool list -plist `cat %s` > %s", dev_disk_file, mount_info_path);
491*bbb1b6f9SApple OSS Distributions	T_QUIET; T_ASSERT_EQ_INT(0, system_legal(cmd), "Fetch ramdisk mount info");
492*bbb1b6f9SApple OSS Distributions
493*bbb1b6f9SApple OSS Distributions	NSURL *mountInfoURL = [NSURL fileURLWithPath:@(mount_info_path) isDirectory:NO];
494*bbb1b6f9SApple OSS Distributions	free(mount_info_path);
495*bbb1b6f9SApple OSS Distributions
496*bbb1b6f9SApple OSS Distributions	NSError *error;
497*bbb1b6f9SApple OSS Distributions	NSDictionary *mountInfo = [NSDictionary dictionaryWithContentsOfURL:mountInfoURL error:&error];
498*bbb1b6f9SApple OSS Distributions	if (!mountInfo) {
499*bbb1b6f9SApple OSS Distributions		T_LOG("Error: %s", error.localizedDescription.UTF8String);
500*bbb1b6f9SApple OSS Distributions	}
501*bbb1b6f9SApple OSS Distributions	T_QUIET; T_ASSERT_NOTNULL(mountInfo, "Read mount info plist");
502*bbb1b6f9SApple OSS Distributions
503*bbb1b6f9SApple OSS Distributions	NSString *mountPoint = nil;
504*bbb1b6f9SApple OSS Distributions	for (NSDictionary *entity in (NSArray *)mountInfo[@"System Entities"]) {
505*bbb1b6f9SApple OSS Distributions		mountPoint = entity[@"Mount Point"];
506*bbb1b6f9SApple OSS Distributions		if (mountPoint) {
507*bbb1b6f9SApple OSS Distributions			break;
508*bbb1b6f9SApple OSS Distributions		}
509*bbb1b6f9SApple OSS Distributions	}
510*bbb1b6f9SApple OSS Distributions	T_QUIET; T_ASSERT_NOTNULL(mountPoint, "Find mount point in mount info plist");
511*bbb1b6f9SApple OSS Distributions
512*bbb1b6f9SApple OSS Distributions	char *mount_path = malloc(PATH_MAX);
513*bbb1b6f9SApple OSS Distributions	atexit_b(^{ free(mount_path); });
514*bbb1b6f9SApple OSS Distributions	strlcpy(mount_path, mountPoint.UTF8String, PATH_MAX);
515*bbb1b6f9SApple OSS Distributions	return mount_path;
516*bbb1b6f9SApple OSS Distributions}
517*bbb1b6f9SApple OSS Distributions
518*bbb1b6f9SApple OSS Distributionsstatic uint64_t
519*bbb1b6f9SApple OSS Distributionstime_for_read(int fd, const char *expected)
520*bbb1b6f9SApple OSS Distributions{
521*bbb1b6f9SApple OSS Distributions	int err;
522*bbb1b6f9SApple OSS Distributions	ssize_t ret;
523*bbb1b6f9SApple OSS Distributions	char buf[READSIZE];
524*bbb1b6f9SApple OSS Distributions	uint64_t start, stop;
525*bbb1b6f9SApple OSS Distributions
526*bbb1b6f9SApple OSS Distributions	bzero(buf, sizeof(buf));
527*bbb1b6f9SApple OSS Distributions	lseek(fd, 0, SEEK_SET);
528*bbb1b6f9SApple OSS Distributions
529*bbb1b6f9SApple OSS Distributions	start = dt_nanoseconds();
530*bbb1b6f9SApple OSS Distributions	ret = read(fd, buf, READSIZE);
531*bbb1b6f9SApple OSS Distributions	stop = dt_nanoseconds();
532*bbb1b6f9SApple OSS Distributions
533*bbb1b6f9SApple OSS Distributions	T_QUIET; T_ASSERT_GE_LONG(ret, 0L, "read from temporary file");
534*bbb1b6f9SApple OSS Distributions	T_QUIET; T_ASSERT_EQ_LONG(ret, READSIZE, "read %ld bytes from temporary file", READSIZE);
535*bbb1b6f9SApple OSS Distributions	err = memcmp(buf, expected, sizeof(buf));
536*bbb1b6f9SApple OSS Distributions	T_QUIET; T_ASSERT_EQ_INT(0, err, "read expected contents from temporary file");
537*bbb1b6f9SApple OSS Distributions
538*bbb1b6f9SApple OSS Distributions	return stop - start;
539*bbb1b6f9SApple OSS Distributions}
540*bbb1b6f9SApple OSS Distributions
541*bbb1b6f9SApple OSS Distributionsstatic void
542*bbb1b6f9SApple OSS Distributionsperf_setup(char **path, int *fd)
543*bbb1b6f9SApple OSS Distributions{
544*bbb1b6f9SApple OSS Distributions	int temp_fd;
545*bbb1b6f9SApple OSS Distributions	char *temp_path;
546*bbb1b6f9SApple OSS Distributions
547*bbb1b6f9SApple OSS Distributions	char *mount_path = mkramdisk();
548*bbb1b6f9SApple OSS Distributions	T_LOG("Using ramdisk mounted at %s", mount_path);
549*bbb1b6f9SApple OSS Distributions
550*bbb1b6f9SApple OSS Distributions	temp_path = *path = malloc(PATH_MAX);
551*bbb1b6f9SApple OSS Distributions	snprintf(temp_path, PATH_MAX, "%s/dmc.XXXXXXXX", mount_path);
552*bbb1b6f9SApple OSS Distributions	atexit_b(^{ free(temp_path); });
553*bbb1b6f9SApple OSS Distributions
554*bbb1b6f9SApple OSS Distributions	T_ASSERT_NOTNULL(mktemp(temp_path), "Create temporary file");
555*bbb1b6f9SApple OSS Distributions	atexit_b(^{ remove(temp_path); });
556*bbb1b6f9SApple OSS Distributions	T_LOG("Using temporary file at %s", temp_path);
557*bbb1b6f9SApple OSS Distributions
558*bbb1b6f9SApple OSS Distributions	temp_fd = *fd = open(temp_path, O_RDWR | O_CREAT);
559*bbb1b6f9SApple OSS Distributions	T_WITH_ERRNO;
560*bbb1b6f9SApple OSS Distributions	T_ASSERT_GE_INT(temp_fd, 0, "Open temporary file for read/write");
561*bbb1b6f9SApple OSS Distributions	atexit_b(^{ close(temp_fd); });
562*bbb1b6f9SApple OSS Distributions	fcntl(temp_fd, F_NOCACHE, 1);
563*bbb1b6f9SApple OSS Distributions}
564*bbb1b6f9SApple OSS Distributions#endif /* !TEST_UNENTITLED */
565