• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: basic fadvise test
4  */
5 #include <errno.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #include <sys/time.h>
13 
14 #include "helpers.h"
15 #include "liburing.h"
16 
17 #define FILE_SIZE	(128 * 1024)
18 #define LOOPS		100
19 #define MIN_LOOPS	10
20 
utime_since(const struct timeval * s,const struct timeval * e)21 static unsigned long long utime_since(const struct timeval *s,
22 				      const struct timeval *e)
23 {
24 	long long sec, usec;
25 
26 	sec = e->tv_sec - s->tv_sec;
27 	usec = (e->tv_usec - s->tv_usec);
28 	if (sec > 0 && usec < 0) {
29 		sec--;
30 		usec += 1000000;
31 	}
32 
33 	sec *= 1000000;
34 	return sec + usec;
35 }
36 
utime_since_now(struct timeval * tv)37 static unsigned long long utime_since_now(struct timeval *tv)
38 {
39 	struct timeval end;
40 
41 	gettimeofday(&end, NULL);
42 	return utime_since(tv, &end);
43 }
44 
do_fadvise(struct io_uring * ring,int fd,off_t offset,off_t len,int advice)45 static int do_fadvise(struct io_uring *ring, int fd, off_t offset, off_t len,
46 		      int advice)
47 {
48 	struct io_uring_sqe *sqe;
49 	struct io_uring_cqe *cqe;
50 	int ret;
51 
52 	sqe = io_uring_get_sqe(ring);
53 	if (!sqe) {
54 		fprintf(stderr, "failed to get sqe\n");
55 		return 1;
56 	}
57 
58 	io_uring_prep_fadvise(sqe, fd, offset, len, advice);
59 	sqe->user_data = advice;
60 	ret = io_uring_submit_and_wait(ring, 1);
61 	if (ret != 1) {
62 		fprintf(stderr, "submit: %d\n", ret);
63 		return 1;
64 	}
65 
66 	ret = io_uring_wait_cqe(ring, &cqe);
67 	if (ret) {
68 		fprintf(stderr, "wait: %d\n", ret);
69 		return 1;
70 	}
71 
72 	ret = cqe->res;
73 	if (ret == -EINVAL || ret == -EBADF) {
74 		fprintf(stdout, "Fadvise not supported, skipping\n");
75 		unlink(".fadvise.tmp");
76 		exit(0);
77 	} else if (ret) {
78 		fprintf(stderr, "cqe->res=%d\n", cqe->res);
79 	}
80 	io_uring_cqe_seen(ring, cqe);
81 	return ret;
82 }
83 
do_read(int fd,char * buf)84 static long do_read(int fd, char *buf)
85 {
86 	struct timeval tv;
87 	int ret;
88 	long t;
89 
90 	ret = lseek(fd, 0, SEEK_SET);
91 	if (ret) {
92 		perror("lseek");
93 		return -1;
94 	}
95 
96 	gettimeofday(&tv, NULL);
97 	ret = read(fd, buf, FILE_SIZE);
98 	t = utime_since_now(&tv);
99 	if (ret < 0) {
100 		perror("read");
101 		return -1;
102 	} else if (ret != FILE_SIZE) {
103 		fprintf(stderr, "short read1: %d\n", ret);
104 		return -1;
105 	}
106 
107 	return t;
108 }
109 
test_fadvise(struct io_uring * ring,const char * filename)110 static int test_fadvise(struct io_uring *ring, const char *filename)
111 {
112 	unsigned long cached_read, uncached_read, cached_read2;
113 	int fd, ret;
114 	char *buf;
115 
116 	fd = open(filename, O_RDONLY);
117 	if (fd < 0) {
118 		perror("open");
119 		return 1;
120 	}
121 
122 	buf = t_malloc(FILE_SIZE);
123 
124 	cached_read = do_read(fd, buf);
125 	if (cached_read == -1)
126 		return 1;
127 
128 	ret = do_fadvise(ring, fd, 0, FILE_SIZE, POSIX_FADV_DONTNEED);
129 	if (ret)
130 		return 1;
131 
132 	uncached_read = do_read(fd, buf);
133 	if (uncached_read == -1)
134 		return 1;
135 
136 	ret = do_fadvise(ring, fd, 0, FILE_SIZE, POSIX_FADV_DONTNEED);
137 	if (ret)
138 		return 1;
139 
140 	ret = do_fadvise(ring, fd, 0, FILE_SIZE, POSIX_FADV_WILLNEED);
141 	if (ret)
142 		return 1;
143 
144 	fsync(fd);
145 
146 	cached_read2 = do_read(fd, buf);
147 	if (cached_read2 == -1)
148 		return 1;
149 
150 	if (cached_read < uncached_read &&
151 	    cached_read2 < uncached_read)
152 		return 0;
153 
154 	return 2;
155 }
156 
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159 	struct io_uring ring;
160 	int ret, i, good, bad;
161 	char *fname;
162 
163 	if (argc > 1) {
164 		fname = argv[1];
165 	} else {
166 		fname = ".fadvise.tmp";
167 		t_create_file(fname, FILE_SIZE);
168 	}
169 	if (io_uring_queue_init(8, &ring, 0)) {
170 		fprintf(stderr, "ring creation failed\n");
171 		goto err;
172 	}
173 
174 	good = bad = 0;
175 	for (i = 0; i < LOOPS; i++) {
176 		ret = test_fadvise(&ring, fname);
177 		if (ret == 1) {
178 			fprintf(stderr, "read_fadvise failed\n");
179 			goto err;
180 		} else if (!ret)
181 			good++;
182 		else if (ret == 2)
183 			bad++;
184 		if (i >= MIN_LOOPS && !bad)
185 			break;
186 	}
187 	if (bad > good) {
188 		fprintf(stderr, "Suspicious timings\n");
189 		goto err;
190 	}
191 
192 	if (fname != argv[1])
193 		unlink(fname);
194 	io_uring_queue_exit(&ring);
195 	return 0;
196 err:
197 	if (fname != argv[1])
198 		unlink(fname);
199 	return 1;
200 }
201