1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright 2010 by Garmin Ltd. or its subsidiaries
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker *
16*288bf522SAndroid Build Coastguard Worker * Performs a simple write/readback test to verify correct functionality
17*288bf522SAndroid Build Coastguard Worker * of direct i/o on a block device node.
18*288bf522SAndroid Build Coastguard Worker */
19*288bf522SAndroid Build Coastguard Worker
20*288bf522SAndroid Build Coastguard Worker /* For large-file support */
21*288bf522SAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS 64
22*288bf522SAndroid Build Coastguard Worker #define _LARGEFILE_SOURCE
23*288bf522SAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
24*288bf522SAndroid Build Coastguard Worker
25*288bf522SAndroid Build Coastguard Worker /* For O_DIRECT */
26*288bf522SAndroid Build Coastguard Worker #define _GNU_SOURCE
27*288bf522SAndroid Build Coastguard Worker
28*288bf522SAndroid Build Coastguard Worker #include <ctype.h>
29*288bf522SAndroid Build Coastguard Worker #include <errno.h>
30*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
31*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
32*288bf522SAndroid Build Coastguard Worker #include <limits.h>
33*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
34*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
35*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
36*288bf522SAndroid Build Coastguard Worker #include <string.h>
37*288bf522SAndroid Build Coastguard Worker #include <sys/ioctl.h>
38*288bf522SAndroid Build Coastguard Worker #include <sys/mman.h>
39*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
40*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
41*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
42*288bf522SAndroid Build Coastguard Worker
43*288bf522SAndroid Build Coastguard Worker #include <linux/fs.h>
44*288bf522SAndroid Build Coastguard Worker
45*288bf522SAndroid Build Coastguard Worker #define NUM_TEST_BLKS 128
46*288bf522SAndroid Build Coastguard Worker
47*288bf522SAndroid Build Coastguard Worker /*
48*288bf522SAndroid Build Coastguard Worker * Allocate page-aligned memory. Could use posix_memalign(3), but some
49*288bf522SAndroid Build Coastguard Worker * systems don't support it. Also pre-faults memory since we'll be using
50*288bf522SAndroid Build Coastguard Worker * it all right away anyway.
51*288bf522SAndroid Build Coastguard Worker */
pagealign_alloc(size_t size)52*288bf522SAndroid Build Coastguard Worker static void *pagealign_alloc(size_t size)
53*288bf522SAndroid Build Coastguard Worker {
54*288bf522SAndroid Build Coastguard Worker void *ret = mmap(NULL, size, PROT_READ | PROT_WRITE,
55*288bf522SAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_LOCKED,
56*288bf522SAndroid Build Coastguard Worker -1, 0);
57*288bf522SAndroid Build Coastguard Worker if (ret == MAP_FAILED) {
58*288bf522SAndroid Build Coastguard Worker perror("mmap");
59*288bf522SAndroid Build Coastguard Worker ret = NULL;
60*288bf522SAndroid Build Coastguard Worker }
61*288bf522SAndroid Build Coastguard Worker return ret;
62*288bf522SAndroid Build Coastguard Worker }
63*288bf522SAndroid Build Coastguard Worker
pagealign_free(void * addr,size_t size)64*288bf522SAndroid Build Coastguard Worker static void pagealign_free(void *addr, size_t size)
65*288bf522SAndroid Build Coastguard Worker {
66*288bf522SAndroid Build Coastguard Worker int ret = munmap(addr, size);
67*288bf522SAndroid Build Coastguard Worker if (ret == -1)
68*288bf522SAndroid Build Coastguard Worker perror("munmap");
69*288bf522SAndroid Build Coastguard Worker }
70*288bf522SAndroid Build Coastguard Worker
do_read(int fd,void * buf,off64_t start,size_t count)71*288bf522SAndroid Build Coastguard Worker static ssize_t do_read(int fd, void *buf, off64_t start, size_t count)
72*288bf522SAndroid Build Coastguard Worker {
73*288bf522SAndroid Build Coastguard Worker ssize_t ret;
74*288bf522SAndroid Build Coastguard Worker size_t bytes_read = 0;
75*288bf522SAndroid Build Coastguard Worker
76*288bf522SAndroid Build Coastguard Worker lseek64(fd, start, SEEK_SET);
77*288bf522SAndroid Build Coastguard Worker
78*288bf522SAndroid Build Coastguard Worker do {
79*288bf522SAndroid Build Coastguard Worker ret = read(fd, (char *)buf + bytes_read, count - bytes_read);
80*288bf522SAndroid Build Coastguard Worker if (ret == -1) {
81*288bf522SAndroid Build Coastguard Worker perror("read");
82*288bf522SAndroid Build Coastguard Worker return -1;
83*288bf522SAndroid Build Coastguard Worker } else if (ret == 0) {
84*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected end-of-file\n");
85*288bf522SAndroid Build Coastguard Worker return -1;
86*288bf522SAndroid Build Coastguard Worker }
87*288bf522SAndroid Build Coastguard Worker bytes_read += ret;
88*288bf522SAndroid Build Coastguard Worker } while (bytes_read < count);
89*288bf522SAndroid Build Coastguard Worker
90*288bf522SAndroid Build Coastguard Worker return bytes_read;
91*288bf522SAndroid Build Coastguard Worker }
92*288bf522SAndroid Build Coastguard Worker
do_write(int fd,const void * buf,off64_t start,size_t count)93*288bf522SAndroid Build Coastguard Worker static ssize_t do_write(int fd, const void *buf, off64_t start, size_t count)
94*288bf522SAndroid Build Coastguard Worker {
95*288bf522SAndroid Build Coastguard Worker ssize_t ret;
96*288bf522SAndroid Build Coastguard Worker size_t bytes_out = 0;
97*288bf522SAndroid Build Coastguard Worker
98*288bf522SAndroid Build Coastguard Worker lseek64(fd, start, SEEK_SET);
99*288bf522SAndroid Build Coastguard Worker
100*288bf522SAndroid Build Coastguard Worker do {
101*288bf522SAndroid Build Coastguard Worker ret = write(fd, (char *)buf + bytes_out, count - bytes_out);
102*288bf522SAndroid Build Coastguard Worker if (ret == -1) {
103*288bf522SAndroid Build Coastguard Worker perror("write");
104*288bf522SAndroid Build Coastguard Worker return -1;
105*288bf522SAndroid Build Coastguard Worker } else if (ret == 0) {
106*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "write returned 0\n");
107*288bf522SAndroid Build Coastguard Worker return -1;
108*288bf522SAndroid Build Coastguard Worker }
109*288bf522SAndroid Build Coastguard Worker bytes_out += ret;
110*288bf522SAndroid Build Coastguard Worker } while (bytes_out < count);
111*288bf522SAndroid Build Coastguard Worker
112*288bf522SAndroid Build Coastguard Worker return bytes_out;
113*288bf522SAndroid Build Coastguard Worker }
114*288bf522SAndroid Build Coastguard Worker
115*288bf522SAndroid Build Coastguard Worker /*
116*288bf522SAndroid Build Coastguard Worker * Initializes test buffer with locally-unique test pattern. High 16-bits of
117*288bf522SAndroid Build Coastguard Worker * each 32-bit word contain first disk block number of the test area, low
118*288bf522SAndroid Build Coastguard Worker * 16-bits contain word offset into test area. The goal is that a given test
119*288bf522SAndroid Build Coastguard Worker * area should never contain the same data as a nearby test area, and that the
120*288bf522SAndroid Build Coastguard Worker * data for a given test area be easily reproducable given the start block and
121*288bf522SAndroid Build Coastguard Worker * test area size.
122*288bf522SAndroid Build Coastguard Worker */
init_test_buf(void * buf,uint64_t start_blk,size_t len)123*288bf522SAndroid Build Coastguard Worker static void init_test_buf(void *buf, uint64_t start_blk, size_t len)
124*288bf522SAndroid Build Coastguard Worker {
125*288bf522SAndroid Build Coastguard Worker uint32_t *data = buf;
126*288bf522SAndroid Build Coastguard Worker size_t i;
127*288bf522SAndroid Build Coastguard Worker
128*288bf522SAndroid Build Coastguard Worker len /= sizeof(uint32_t);
129*288bf522SAndroid Build Coastguard Worker for (i = 0; i < len; i++)
130*288bf522SAndroid Build Coastguard Worker data[i] = (start_blk & 0xFFFF) << 16 | (i & 0xFFFF);
131*288bf522SAndroid Build Coastguard Worker }
132*288bf522SAndroid Build Coastguard Worker
dump_hex(const void * buf,int len)133*288bf522SAndroid Build Coastguard Worker static void dump_hex(const void *buf, int len)
134*288bf522SAndroid Build Coastguard Worker {
135*288bf522SAndroid Build Coastguard Worker const uint8_t *data = buf;
136*288bf522SAndroid Build Coastguard Worker int i;
137*288bf522SAndroid Build Coastguard Worker char ascii_buf[17];
138*288bf522SAndroid Build Coastguard Worker
139*288bf522SAndroid Build Coastguard Worker ascii_buf[16] = '\0';
140*288bf522SAndroid Build Coastguard Worker
141*288bf522SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
142*288bf522SAndroid Build Coastguard Worker int val = data[i];
143*288bf522SAndroid Build Coastguard Worker int off = i % 16;
144*288bf522SAndroid Build Coastguard Worker
145*288bf522SAndroid Build Coastguard Worker if (off == 0)
146*288bf522SAndroid Build Coastguard Worker printf("%08x ", i);
147*288bf522SAndroid Build Coastguard Worker printf("%02x ", val);
148*288bf522SAndroid Build Coastguard Worker ascii_buf[off] = isprint(val) ? val : '.';
149*288bf522SAndroid Build Coastguard Worker if (off == 15)
150*288bf522SAndroid Build Coastguard Worker printf(" %-16s\n", ascii_buf);
151*288bf522SAndroid Build Coastguard Worker }
152*288bf522SAndroid Build Coastguard Worker
153*288bf522SAndroid Build Coastguard Worker i %= 16;
154*288bf522SAndroid Build Coastguard Worker if (i) {
155*288bf522SAndroid Build Coastguard Worker ascii_buf[i] = '\0';
156*288bf522SAndroid Build Coastguard Worker while (i++ < 16)
157*288bf522SAndroid Build Coastguard Worker printf(" ");
158*288bf522SAndroid Build Coastguard Worker printf(" %-16s\n", ascii_buf);
159*288bf522SAndroid Build Coastguard Worker }
160*288bf522SAndroid Build Coastguard Worker }
161*288bf522SAndroid Build Coastguard Worker
update_progress(int current,int total)162*288bf522SAndroid Build Coastguard Worker static void update_progress(int current, int total)
163*288bf522SAndroid Build Coastguard Worker {
164*288bf522SAndroid Build Coastguard Worker double pct_done = (double)current * 100 / total;
165*288bf522SAndroid Build Coastguard Worker printf("Testing area %d/%d (%6.2f%% complete)\r", current, total,
166*288bf522SAndroid Build Coastguard Worker pct_done);
167*288bf522SAndroid Build Coastguard Worker fflush(stdout);
168*288bf522SAndroid Build Coastguard Worker }
169*288bf522SAndroid Build Coastguard Worker
main(int argc,const char * argv[])170*288bf522SAndroid Build Coastguard Worker int main(int argc, const char *argv[])
171*288bf522SAndroid Build Coastguard Worker {
172*288bf522SAndroid Build Coastguard Worker int ret = 1;
173*288bf522SAndroid Build Coastguard Worker const char *path;
174*288bf522SAndroid Build Coastguard Worker int fd;
175*288bf522SAndroid Build Coastguard Worker struct stat stat;
176*288bf522SAndroid Build Coastguard Worker void *read_buf = NULL, *write_buf = NULL;
177*288bf522SAndroid Build Coastguard Worker int blk_size;
178*288bf522SAndroid Build Coastguard Worker uint64_t num_blks;
179*288bf522SAndroid Build Coastguard Worker size_t test_size;
180*288bf522SAndroid Build Coastguard Worker int test_areas, i;
181*288bf522SAndroid Build Coastguard Worker
182*288bf522SAndroid Build Coastguard Worker if (argc != 2) {
183*288bf522SAndroid Build Coastguard Worker printf("Usage: directiotest blkdev_path\n");
184*288bf522SAndroid Build Coastguard Worker exit(1);
185*288bf522SAndroid Build Coastguard Worker }
186*288bf522SAndroid Build Coastguard Worker
187*288bf522SAndroid Build Coastguard Worker path = argv[1];
188*288bf522SAndroid Build Coastguard Worker fd = open(path, O_RDWR | O_DIRECT | O_LARGEFILE);
189*288bf522SAndroid Build Coastguard Worker if (fd == -1) {
190*288bf522SAndroid Build Coastguard Worker perror("open");
191*288bf522SAndroid Build Coastguard Worker exit(1);
192*288bf522SAndroid Build Coastguard Worker }
193*288bf522SAndroid Build Coastguard Worker if (fstat(fd, &stat) == -1) {
194*288bf522SAndroid Build Coastguard Worker perror("stat");
195*288bf522SAndroid Build Coastguard Worker goto cleanup;
196*288bf522SAndroid Build Coastguard Worker } else if (!S_ISBLK(stat.st_mode)) {
197*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "%s is not a block device\n", path);
198*288bf522SAndroid Build Coastguard Worker goto cleanup;
199*288bf522SAndroid Build Coastguard Worker }
200*288bf522SAndroid Build Coastguard Worker
201*288bf522SAndroid Build Coastguard Worker if (ioctl(fd, BLKSSZGET, &blk_size) == -1) {
202*288bf522SAndroid Build Coastguard Worker perror("ioctl");
203*288bf522SAndroid Build Coastguard Worker goto cleanup;
204*288bf522SAndroid Build Coastguard Worker }
205*288bf522SAndroid Build Coastguard Worker if (ioctl(fd, BLKGETSIZE64, &num_blks) == -1) {
206*288bf522SAndroid Build Coastguard Worker perror("ioctl");
207*288bf522SAndroid Build Coastguard Worker goto cleanup;
208*288bf522SAndroid Build Coastguard Worker }
209*288bf522SAndroid Build Coastguard Worker num_blks /= blk_size;
210*288bf522SAndroid Build Coastguard Worker
211*288bf522SAndroid Build Coastguard Worker test_size = (size_t)blk_size * NUM_TEST_BLKS;
212*288bf522SAndroid Build Coastguard Worker read_buf = pagealign_alloc(test_size);
213*288bf522SAndroid Build Coastguard Worker write_buf = pagealign_alloc(test_size);
214*288bf522SAndroid Build Coastguard Worker if (!read_buf || !write_buf) {
215*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Error allocating test buffers\n");
216*288bf522SAndroid Build Coastguard Worker goto cleanup;
217*288bf522SAndroid Build Coastguard Worker }
218*288bf522SAndroid Build Coastguard Worker
219*288bf522SAndroid Build Coastguard Worker /*
220*288bf522SAndroid Build Coastguard Worker * Start the actual test. Go through the entire device, writing
221*288bf522SAndroid Build Coastguard Worker * locally-unique patern to each test block and then reading it
222*288bf522SAndroid Build Coastguard Worker * back.
223*288bf522SAndroid Build Coastguard Worker */
224*288bf522SAndroid Build Coastguard Worker if (num_blks / NUM_TEST_BLKS > INT_MAX) {
225*288bf522SAndroid Build Coastguard Worker printf("Warning: Device too large for test variables\n");
226*288bf522SAndroid Build Coastguard Worker printf("Entire device will not be tested\n");
227*288bf522SAndroid Build Coastguard Worker test_areas = INT_MAX;
228*288bf522SAndroid Build Coastguard Worker } else {
229*288bf522SAndroid Build Coastguard Worker test_areas = num_blks / NUM_TEST_BLKS;
230*288bf522SAndroid Build Coastguard Worker }
231*288bf522SAndroid Build Coastguard Worker
232*288bf522SAndroid Build Coastguard Worker printf("Starting test\n");
233*288bf522SAndroid Build Coastguard Worker
234*288bf522SAndroid Build Coastguard Worker for (i = 0; i < test_areas; i++) {
235*288bf522SAndroid Build Coastguard Worker uint64_t cur_blk = (uint64_t)i * NUM_TEST_BLKS;
236*288bf522SAndroid Build Coastguard Worker
237*288bf522SAndroid Build Coastguard Worker update_progress(i + 1, test_areas);
238*288bf522SAndroid Build Coastguard Worker
239*288bf522SAndroid Build Coastguard Worker init_test_buf(write_buf, cur_blk, test_size);
240*288bf522SAndroid Build Coastguard Worker
241*288bf522SAndroid Build Coastguard Worker if (do_write(fd, write_buf, cur_blk * blk_size, test_size) !=
242*288bf522SAndroid Build Coastguard Worker (ssize_t)test_size) {
243*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "write failed, aborting test\n");
244*288bf522SAndroid Build Coastguard Worker goto cleanup;
245*288bf522SAndroid Build Coastguard Worker }
246*288bf522SAndroid Build Coastguard Worker if (do_read(fd, read_buf, cur_blk * blk_size, test_size) !=
247*288bf522SAndroid Build Coastguard Worker (ssize_t)test_size) {
248*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "read failed, aborting test\n");
249*288bf522SAndroid Build Coastguard Worker goto cleanup;
250*288bf522SAndroid Build Coastguard Worker }
251*288bf522SAndroid Build Coastguard Worker
252*288bf522SAndroid Build Coastguard Worker if (memcmp(write_buf, read_buf, test_size)) {
253*288bf522SAndroid Build Coastguard Worker printf("Readback verification failed at block %" PRIu64 "\n\n",
254*288bf522SAndroid Build Coastguard Worker cur_blk);
255*288bf522SAndroid Build Coastguard Worker printf("Written data:\n");
256*288bf522SAndroid Build Coastguard Worker dump_hex(write_buf, test_size);
257*288bf522SAndroid Build Coastguard Worker printf("\nRead data:\n");
258*288bf522SAndroid Build Coastguard Worker dump_hex(read_buf, test_size);
259*288bf522SAndroid Build Coastguard Worker goto cleanup;
260*288bf522SAndroid Build Coastguard Worker }
261*288bf522SAndroid Build Coastguard Worker }
262*288bf522SAndroid Build Coastguard Worker
263*288bf522SAndroid Build Coastguard Worker printf("\nTest complete\n");
264*288bf522SAndroid Build Coastguard Worker ret = 0;
265*288bf522SAndroid Build Coastguard Worker
266*288bf522SAndroid Build Coastguard Worker cleanup:
267*288bf522SAndroid Build Coastguard Worker if (read_buf)
268*288bf522SAndroid Build Coastguard Worker pagealign_free(read_buf, test_size);
269*288bf522SAndroid Build Coastguard Worker if (write_buf)
270*288bf522SAndroid Build Coastguard Worker pagealign_free(write_buf, test_size);
271*288bf522SAndroid Build Coastguard Worker close(fd);
272*288bf522SAndroid Build Coastguard Worker return ret;
273*288bf522SAndroid Build Coastguard Worker }
274