2 * Ceph - scalable distributed file system
4 * Copyright (C) 2011 New Dream Network
6 * This is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software
9 * Foundation. See file COPYING.
21 #include <sys/types.h>
28 * This test does some I/O using O_DIRECT.
30 * Semantics of O_DIRECT can be found at http://lwn.net/Articles/348739/
34 static int g_num_pages = 100;
36 static int g_duration = 10;
47 } __attribute__((packed));
51 static char temp_file[] = "direct_io_temp_file_XXXXXX";
53 static int safe_write(int fd, const void *buf, signed int len)
55 const char *b = (const char*)buf;
56 /* Handle EINTR and short writes */
58 int res = write(fd, b, len);
72 static int do_read(int fd, char *buf, int buf_sz)
74 /* We assume no short reads or EINTR. It's not really clear how
75 * those things interact with O_DIRECT. */
76 int ret = read(fd, buf, buf_sz);
79 printf("do_read: error: %d (%s)\n", err, strerror(err));
83 printf("do_read: short read\n");
89 static int setup_temp_file(void)
92 int64_t num_chunks, i;
94 if (page_size % sizeof(struct chunk)) {
95 printf("setup_big_file: page_size doesn't divide evenly "
96 "into data blocks.\n");
100 fd = mkstemp(temp_file);
103 printf("setup_big_file: mkostemps failed with error %d\n", err);
107 num_chunks = g_num_pages * (page_size / sizeof(struct chunk));
108 for (i = 0; i < num_chunks; ++i) {
111 memset(&c, 0, sizeof(c));
112 c.offset = i * sizeof(struct chunk);
119 c.not_offset = ~c.offset;
120 ret = safe_write(fd, &c, sizeof(struct chunk));
122 printf("setup_big_file: safe_write failed with "
124 TEMP_FAILURE_RETRY(close(fd));
129 TEMP_FAILURE_RETRY(close(fd));
133 static int verify_chunk(const struct chunk *c, uint64_t offset)
135 if (c->offset != offset) {
136 printf("verify_chunk(%" PRId64 "): bad offset value (got: %"
137 PRId64 ", expected: %" PRId64 "\n", offset, c->offset, offset);
141 printf("verify_chunk(%" PRId64 "): bad pad0 value\n", offset);
145 printf("verify_chunk(%" PRId64 "): bad pad1 value\n", offset);
149 printf("verify_chunk(%" PRId64 "): bad pad2 value\n", offset);
153 printf("verify_chunk(%" PRId64 "): bad pad3 value\n", offset);
157 printf("verify_chunk(%" PRId64 "): bad pad4 value\n", offset);
161 printf("verify_chunk(%" PRId64 "): bad pad5 value\n", offset);
164 if (c->not_offset != ~offset) {
165 printf("verify_chunk(%" PRId64 "): bad not_offset value\n",
172 static int do_o_direct_reads(void)
177 time_t cur_time, end_time;
178 ret = posix_memalign(&buf, page_size, page_size);
180 printf("do_o_direct_reads: posix_memalign returned %d\n", ret);
184 fd = open(temp_file, O_RDONLY | O_DIRECT);
187 printf("do_o_direct_reads: error opening fd: %d\n", ret);
191 // read the first chunk and see if it looks OK
192 ret = do_read(fd, buf, page_size);
195 ret = verify_chunk((struct chunk*)buf, 0);
199 // read some random chunks and see how they look
200 cur_time = time(NULL);
201 end_time = cur_time + g_duration;
210 page = rand_r(&seed) % g_num_pages;
213 if (lseek64(fd, offset, SEEK_SET) == -1) {
215 printf("lseek64(%" PRId64 ") failed: error %d (%s)\n",
216 offset, err, strerror(err));
219 ret = do_read(fd, buf, page_size);
222 ret = verify_chunk((struct chunk*)buf, offset);
225 next_time = time(NULL);
226 if (next_time > cur_time) {
229 cur_time = next_time;
230 } while (time(NULL) < end_time);
232 printf("\ndo_o_direct_reads: SUCCESS\n");
234 TEMP_FAILURE_RETRY(close(fd));
241 static void usage(char *argv0)
243 printf("%s: tests direct I/O\n", argv0);
244 printf("-d <seconds>: sets duration to <seconds>\n");
245 printf("-h: this help\n");
246 printf("-p <pages>: sets number of pages to allocate\n");
249 static void parse_args(int argc, char *argv[])
252 while ((c = getopt (argc, argv, "d:hp:")) != -1) {
255 g_duration = atoi(optarg);
256 if (g_duration <= 0) {
257 printf("tried to set invalid value of "
258 "g_duration: %d\n", g_num_pages);
267 g_num_pages = atoi(optarg);
268 if (g_num_pages <= 0) {
269 printf("tried to set invalid value of "
270 "g_num_pages: %d\n", g_num_pages);
286 int main(int argc, char *argv[])
290 parse_args(argc, argv);
292 setvbuf(stdout, NULL, _IONBF, 0);
294 page_size = getpagesize();
296 ret = setup_temp_file();
298 printf("setup_temp_file failed with error %d\n", ret);
302 ret = do_o_direct_reads();
304 printf("do_o_direct_reads failed with error %d\n", ret);
305 goto unlink_temp_file;