• 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 
do_fadvise(struct io_uring * ring,int fd,off_t offset,off_t len,int advice)21 static int do_fadvise(struct io_uring *ring, int fd, off_t offset, off_t len,
22 		      int advice)
23 {
24 	struct io_uring_sqe *sqe;
25 	struct io_uring_cqe *cqe;
26 	int ret;
27 
28 	sqe = io_uring_get_sqe(ring);
29 	if (!sqe) {
30 		fprintf(stderr, "failed to get sqe\n");
31 		return 1;
32 	}
33 
34 	io_uring_prep_fadvise(sqe, fd, offset, len, advice);
35 	sqe->user_data = advice;
36 	ret = io_uring_submit_and_wait(ring, 1);
37 	if (ret != 1) {
38 		fprintf(stderr, "submit: %d\n", ret);
39 		return 1;
40 	}
41 
42 	ret = io_uring_wait_cqe(ring, &cqe);
43 	if (ret) {
44 		fprintf(stderr, "wait: %d\n", ret);
45 		return 1;
46 	}
47 
48 	ret = cqe->res;
49 	if (ret == -EINVAL || ret == -EBADF) {
50 		fprintf(stdout, "Fadvise not supported, skipping\n");
51 		unlink(".fadvise.tmp");
52 		exit(T_EXIT_SKIP);
53 	} else if (ret) {
54 		fprintf(stderr, "cqe->res=%d\n", cqe->res);
55 	}
56 	io_uring_cqe_seen(ring, cqe);
57 	return ret;
58 }
59 
do_read(int fd,char * buf)60 static long do_read(int fd, char *buf)
61 {
62 	struct timeval tv;
63 	int ret;
64 	long t;
65 
66 	ret = lseek(fd, 0, SEEK_SET);
67 	if (ret) {
68 		perror("lseek");
69 		return -1;
70 	}
71 
72 	gettimeofday(&tv, NULL);
73 	ret = read(fd, buf, FILE_SIZE);
74 	t = utime_since_now(&tv);
75 	if (ret < 0) {
76 		perror("read");
77 		return -1;
78 	} else if (ret != FILE_SIZE) {
79 		fprintf(stderr, "short read1: %d\n", ret);
80 		return -1;
81 	}
82 
83 	return t;
84 }
85 
test_fadvise(struct io_uring * ring,const char * filename)86 static int test_fadvise(struct io_uring *ring, const char *filename)
87 {
88 	unsigned long cached_read, uncached_read, cached_read2;
89 	int fd, ret;
90 	char *buf;
91 
92 	fd = open(filename, O_RDONLY);
93 	if (fd < 0) {
94 		if (errno == EPERM || errno == EACCES)
95 			return T_EXIT_SKIP;
96 		perror("open");
97 		return 1;
98 	}
99 
100 	buf = t_malloc(FILE_SIZE);
101 
102 	cached_read = do_read(fd, buf);
103 	if (cached_read == -1)
104 		return 1;
105 
106 	ret = do_fadvise(ring, fd, 0, FILE_SIZE, POSIX_FADV_DONTNEED);
107 	if (ret)
108 		return 1;
109 
110 	uncached_read = do_read(fd, buf);
111 	if (uncached_read == -1)
112 		return 1;
113 
114 	ret = do_fadvise(ring, fd, 0, FILE_SIZE, POSIX_FADV_DONTNEED);
115 	if (ret)
116 		return 1;
117 
118 	ret = do_fadvise(ring, fd, 0, FILE_SIZE, POSIX_FADV_WILLNEED);
119 	if (ret)
120 		return 1;
121 
122 	fsync(fd);
123 
124 	cached_read2 = do_read(fd, buf);
125 	if (cached_read2 == -1)
126 		return 1;
127 
128 	if (cached_read < uncached_read &&
129 		cached_read2 < uncached_read) {
130 		free(buf);
131 		return 0;
132 	}
133 
134 	free(buf);
135 	return 2;
136 }
137 
main(int argc,char * argv[])138 int main(int argc, char *argv[])
139 {
140 	struct io_uring ring;
141 	int ret, i, good, bad;
142 	char *fname;
143 
144 	if (argc > 1) {
145 		fname = argv[1];
146 	} else {
147 		fname = ".fadvise.tmp";
148 		t_create_file(fname, FILE_SIZE);
149 	}
150 	if (io_uring_queue_init(8, &ring, 0)) {
151 		fprintf(stderr, "ring creation failed\n");
152 		goto err;
153 	}
154 
155 	good = bad = 0;
156 	for (i = 0; i < LOOPS; i++) {
157 		ret = test_fadvise(&ring, fname);
158 		if (ret == T_EXIT_SKIP)
159 			return T_EXIT_SKIP;
160 		if (ret == 1) {
161 			fprintf(stderr, "read_fadvise failed\n");
162 			goto err;
163 		} else if (!ret)
164 			good++;
165 		else if (ret == 2)
166 			bad++;
167 		if (i >= MIN_LOOPS && !bad)
168 			break;
169 	}
170 
171 	/* too hard to reliably test, just ignore */
172 	if ((0) && bad > good) {
173 		fprintf(stderr, "Suspicious timings\n");
174 		goto err;
175 	}
176 
177 	if (fname != argv[1])
178 		unlink(fname);
179 	io_uring_queue_exit(&ring);
180 	return T_EXIT_PASS;
181 err:
182 	if (fname != argv[1])
183 		unlink(fname);
184 	return T_EXIT_FAIL;
185 }
186