• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <assert.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/xattr.h>
7 #include <unistd.h>
8 
9 #include "helpers.h"
10 #include "liburing.h"
11 
12 static int no_xattr;
13 
14 /* Define constants. */
15 #define XATTR_SIZE  255
16 #define QUEUE_DEPTH 32
17 
18 #define FILENAME    "xattr.test"
19 #define KEY1        "user.val1"
20 #define KEY2        "user.val2"
21 #define VALUE1      "value1"
22 #define VALUE2      "value2-a-lot-longer"
23 
24 
25 /* Call fsetxattr. */
io_uring_fsetxattr(struct io_uring * ring,int fd,const char * name,const void * value,size_t size,int flags)26 static int io_uring_fsetxattr(struct io_uring *ring, int fd, const char *name,
27 			      const void *value, size_t size, int flags)
28 {
29 	struct io_uring_sqe *sqe;
30 	struct io_uring_cqe *cqe;
31 	int ret;
32 
33 	sqe = io_uring_get_sqe(ring);
34 	if (!sqe) {
35 		fprintf(stderr, "Error cannot get sqe\n");
36 		return -1;
37 	}
38 
39 	io_uring_prep_fsetxattr(sqe, fd, name, value, flags, size);
40 
41 	ret = io_uring_submit(ring);
42 	if (ret != 1) {
43 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
44 		return -1;
45 	}
46 
47 	ret = io_uring_wait_cqe(ring, &cqe);
48 	if (ret) {
49 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
50 		return -1;
51 	}
52 
53 	ret = cqe->res;
54 	if (ret < 0) {
55 		if (cqe->res == -EINVAL || cqe->res == -EOPNOTSUPP)
56 			no_xattr = 1;
57 	}
58 	io_uring_cqe_seen(ring, cqe);
59 	return ret;
60 }
61 
62 /* Submit fgetxattr request. */
io_uring_fgetxattr(struct io_uring * ring,int fd,const char * name,void * value,size_t size)63 static int io_uring_fgetxattr(struct io_uring *ring, int fd, const char *name,
64 			      void *value, size_t size)
65 {
66 	struct io_uring_sqe *sqe;
67 	struct io_uring_cqe *cqe;
68 	int ret;
69 
70 	sqe = io_uring_get_sqe(ring);
71 	if (!sqe) {
72 		fprintf(stderr, "Error cannot get sqe\n");
73 		return -1;
74 	}
75 
76 	io_uring_prep_fgetxattr(sqe, fd, name, value, size);
77 
78 	ret = io_uring_submit(ring);
79 	if (ret != 1) {
80 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
81 		return -1;
82 	}
83 
84 	ret = io_uring_wait_cqe(ring, &cqe);
85 	if (ret) {
86 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
87 		return -1;
88 	}
89 
90 	ret = cqe->res;
91 	if (ret == -1) {
92 		fprintf(stderr, "Error couldn'tget value\n");
93 		return -1;
94 	}
95 
96 	io_uring_cqe_seen(ring, cqe);
97 	return ret;
98 }
99 
100 /* Call setxattr. */
io_uring_setxattr(struct io_uring * ring,const char * path,const char * name,const void * value,size_t size,int flags)101 static int io_uring_setxattr(struct io_uring *ring, const char *path,
102 			     const char *name, const void *value, size_t size,
103 			     int flags)
104 {
105 	struct io_uring_sqe *sqe;
106 	struct io_uring_cqe *cqe;
107 	int ret;
108 
109 	sqe = io_uring_get_sqe(ring);
110 	if (!sqe) {
111 		fprintf(stderr, "Error cannot get sqe\n");
112 		return -1;
113 	}
114 
115 	io_uring_prep_setxattr(sqe, name, value, path, flags, size);
116 
117 	ret = io_uring_submit_and_wait(ring, 1);
118 	if (ret != 1) {
119 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
120 		return -1;
121 	}
122 
123 	ret = io_uring_wait_cqe(ring, &cqe);
124 	if (ret) {
125 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
126 		return -1;
127 	}
128 
129 	ret = cqe->res;
130 	if (ret < 0) {
131 		if (ret == -EINVAL || ret == -EOPNOTSUPP)
132 			no_xattr = 1;
133 	}
134 	io_uring_cqe_seen(ring, cqe);
135 	return ret;
136 }
137 
138 /* Submit getxattr request. */
io_uring_getxattr(struct io_uring * ring,const char * path,const char * name,void * value,size_t size)139 static int io_uring_getxattr(struct io_uring *ring, const char *path,
140 			     const char *name, void *value, size_t size)
141 {
142 	struct io_uring_sqe *sqe;
143 	struct io_uring_cqe *cqe;
144 	int ret;
145 
146 	sqe = io_uring_get_sqe(ring);
147 	if (!sqe) {
148 		fprintf(stderr, "Error cannot get sqe\n");
149 		return -1;
150 	}
151 
152 	io_uring_prep_getxattr(sqe, name, value, path, size);
153 
154 	ret = io_uring_submit(ring);
155 	if (ret != 1) {
156 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
157 		return -1;
158 	}
159 
160 	ret = io_uring_wait_cqe(ring, &cqe);
161 	if (ret) {
162 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
163 		return -1;
164 	}
165 
166 	ret = cqe->res;
167 	if (ret == -1) {
168 		fprintf(stderr, "Error couldn'tget value\n");
169 		return -1;
170 	}
171 
172 	io_uring_cqe_seen(ring, cqe);
173 	return ret;
174 }
175 
176 /* Test driver for fsetxattr and fgetxattr. */
test_fxattr(void)177 static int test_fxattr(void)
178 {
179 	int rc = 0;
180 	size_t value_len;
181 	struct io_uring ring;
182 	char value[XATTR_SIZE];
183 
184 	/* Init io-uring queue. */
185 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
186 	if (ret) {
187 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
188 		return -1;
189 	}
190 
191 	/* Create the test file. */
192 	int fd = open(FILENAME, O_CREAT | O_RDWR, 0644);
193 	if (fd < 0) {
194 		fprintf(stderr, "Error: cannot open file: ret=%d\n", fd);
195 		return -1;
196 	}
197 
198 	/* Test writing attributes. */
199 	if (io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, strlen(VALUE1), 0) < 0) {
200 		if (no_xattr) {
201 			fprintf(stdout, "No xattr support, skipping\n");
202 			goto Exit;
203 		}
204 		fprintf(stderr, "Error fsetxattr cannot write key1\n");
205 		rc = -1;
206 		goto Exit;
207 	}
208 
209 	if (io_uring_fsetxattr(&ring, fd, KEY2, VALUE2, strlen(VALUE2), 0) < 0) {
210 		fprintf(stderr, "Error fsetxattr cannot write key1\n");
211 		rc = -1;
212 		goto Exit;
213 	}
214 
215 	/* Test reading attributes. */
216 	value_len = io_uring_fgetxattr(&ring, fd, KEY1, value, XATTR_SIZE);
217 	if (value_len != strlen(VALUE1) || strncmp(value, VALUE1, value_len)) {
218 		fprintf(stderr, "Error: fgetxattr expected value: %s, returned value: %s\n", VALUE1, value);
219 		rc = -1;
220 		goto Exit;
221 	}
222 
223 	value_len = io_uring_fgetxattr(&ring, fd, KEY2, value, XATTR_SIZE);
224 	if (value_len != strlen(VALUE2) || strncmp(value, VALUE2, value_len)) {
225 		fprintf(stderr, "Error: fgetxattr expected value: %s, returned value: %s\n", VALUE2, value);
226 		rc = -1;
227 		goto Exit;
228 	}
229 
230 	/* Cleanup. */
231 Exit:
232 	close(fd);
233 	unlink(FILENAME);
234 
235 	io_uring_queue_exit(&ring);
236 
237 	return rc;
238 }
239 
240 /* Test driver for setxattr and getxattr. */
test_xattr(void)241 static int test_xattr(void)
242 {
243 	int rc = 0;
244 	int value_len;
245 	struct io_uring ring;
246 	char value[XATTR_SIZE];
247 
248 	/* Init io-uring queue. */
249 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
250 	if (ret) {
251 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
252 		return -1;
253 	}
254 
255 	/* Create the test file. */
256 	t_create_file(FILENAME, 0);
257 
258 	/* Test writing attributes. */
259 	if (io_uring_setxattr(&ring, FILENAME, KEY1, VALUE1, strlen(VALUE1), 0) < 0) {
260 		fprintf(stderr, "Error setxattr cannot write key1\n");
261 		rc = -1;
262 		goto Exit;
263 	}
264 
265 	if (io_uring_setxattr(&ring, FILENAME, KEY2, VALUE2, strlen(VALUE2), 0) < 0) {
266 		fprintf(stderr, "Error setxattr cannot write key1\n");
267 		rc = -1;
268 		goto Exit;
269 	}
270 
271 	/* Test reading attributes. */
272 	value_len = io_uring_getxattr(&ring, FILENAME, KEY1, value, XATTR_SIZE);
273 	if (value_len != strlen(VALUE1) || strncmp(value, VALUE1, value_len)) {
274 		fprintf(stderr, "Error: getxattr expected value: %s, returned value: %s\n", VALUE1, value);
275 		rc = -1;
276 		goto Exit;
277 	}
278 
279 	value_len = io_uring_getxattr(&ring, FILENAME, KEY2, value, XATTR_SIZE);
280 	if (value_len != strlen(VALUE2) || strncmp(value, VALUE2, value_len)) {
281 		fprintf(stderr, "Error: getxattr expected value: %s, returned value: %s\n", VALUE2, value);
282 		rc = -1;
283 		goto Exit;
284 	}
285 
286 	/* Cleanup. */
287 Exit:
288 	io_uring_queue_exit(&ring);
289 	unlink(FILENAME);
290 
291 	return rc;
292 }
293 
294 /* Test driver for failure cases of fsetxattr and fgetxattr. */
test_failure_fxattr(void)295 static int test_failure_fxattr(void)
296 {
297 	struct io_uring ring;
298 	char value[XATTR_SIZE];
299 
300 	/* Init io-uring queue. */
301 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
302 	if (ret) {
303 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
304 		return -1;
305 	}
306 
307 	/* Create the test file. */
308 	int fd = open(FILENAME, O_CREAT | O_RDWR, 0644);
309 	if (fd < 0) {
310 		fprintf(stderr, "Error: cannot open file: ret=%d\n", fd);
311 		return -1;
312 	}
313 
314 	/* Test writing attributes. */
315 	if (io_uring_fsetxattr(&ring, -1, KEY1, VALUE1, strlen(VALUE1), 0) >= 0)
316 		return 1;
317 	if (io_uring_fsetxattr(&ring, fd, NULL, VALUE1, strlen(VALUE1), 0) >= 0)
318 		return 1;
319 	if (io_uring_fsetxattr(&ring, fd, KEY1, NULL,   strlen(VALUE1), 0) >= 0)
320 		return 1;
321 	if (io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, 0, 0) != 0)
322 		return 1;
323 	if (io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, -1, 0) >= 0)
324 		return 1;
325 
326 	/* Test reading attributes. */
327 	if (io_uring_fgetxattr(&ring, -1, KEY1, value, XATTR_SIZE) >= 0)
328 		return 1;
329 	if (io_uring_fgetxattr(&ring, fd, NULL, value, XATTR_SIZE) >= 0)
330 		return 1;
331 	if (io_uring_fgetxattr(&ring, fd, KEY1, value, 0) != 0)
332 		return 1;
333 
334 	/* Cleanup. */
335 	close(fd);
336 	unlink(FILENAME);
337 	io_uring_queue_exit(&ring);
338 	return 0;
339 }
340 
341 
342 /* Test driver for failure cases for setxattr and getxattr. */
test_failure_xattr(void)343 static int test_failure_xattr(void)
344 {
345 	struct io_uring ring;
346 	char value[XATTR_SIZE];
347 
348 	/* Init io-uring queue. */
349 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
350 	if (ret) {
351 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
352 		return -1;
353 	}
354 
355 	/* Create the test file. */
356 	t_create_file(FILENAME, 0);
357 
358 	/* Test writing attributes. */
359 	if (io_uring_setxattr(&ring, "complete garbage", KEY1, VALUE1, strlen(VALUE1), 0) >= 0)
360 		return 1;
361 	if (io_uring_setxattr(&ring, NULL,     KEY1, VALUE1, strlen(VALUE1), 0) >= 0)
362 		return 1;
363 	if (io_uring_setxattr(&ring, FILENAME, NULL, VALUE1, strlen(VALUE1), 0) >= 0)
364 		return 1;
365 	if (io_uring_setxattr(&ring, FILENAME, KEY1, NULL,   strlen(VALUE1), 0) >= 0)
366 		return 1;
367 	if (io_uring_setxattr(&ring, FILENAME, KEY1, VALUE1, 0, 0) != 0)
368 		return 1;
369 
370 	/* Test reading attributes. */
371 	if (io_uring_getxattr(&ring, "complete garbage", KEY1, value, XATTR_SIZE) >= 0)
372 		return 1;
373 	if (io_uring_getxattr(&ring, NULL,     KEY1, value, XATTR_SIZE) >= 0)
374 		return 1;
375 	if (io_uring_getxattr(&ring, FILENAME, NULL, value, XATTR_SIZE) >= 0)
376 		return 1;
377 	if (io_uring_getxattr(&ring, FILENAME, KEY1, NULL,  XATTR_SIZE) != 0)
378 		return 1;
379 	if (io_uring_getxattr(&ring, FILENAME, KEY1, value, 0) != 0)
380 		return 1;
381 
382 	/* Cleanup. */
383 	io_uring_queue_exit(&ring);
384 	unlink(FILENAME);
385 	return 0;
386 }
387 
388 /* Test for invalid SQE, this will cause a segmentation fault if enabled. */
test_invalid_sqe(void)389 static int test_invalid_sqe(void)
390 {
391 #ifdef DESTRUCTIVE_TEST
392 	struct io_uring_sqe *sqe = NULL;
393 	struct io_uring_cqe *cqe = NULL;
394 	struct io_uring ring;
395 
396 	/* Init io-uring queue. */
397 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
398 	if (ret) {
399 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
400 		return -1;
401 	}
402 
403 	/* Pass invalid SQE. */
404 	io_uring_prep_setxattr(sqe, FILENAME, KEY1, VALUE1, strlen(VALUE1), 0);
405 
406 	ret = io_uring_submit(&ring);
407 	if (ret != 1) {
408 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
409 		return -1;
410 	}
411 
412 	ret = io_uring_wait_cqe(&ring, &cqe);
413 	if (ret) {
414 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
415 		return -1;
416 	}
417 
418 	ret = cqe->res;
419 	io_uring_cqe_seen(&ring, cqe);
420 
421 	return ret;
422 #else
423 	return 0;
424 #endif
425 }
426 
427 /* Test driver. */
main(int argc,char * argv[])428 int main(int argc, char *argv[])
429 {
430 	if (argc > 1)
431 		return 0;
432 
433 	if (test_fxattr())
434 		return EXIT_FAILURE;
435 	if (no_xattr)
436 		return EXIT_SUCCESS;
437 	if (test_xattr() || test_failure_fxattr() || test_failure_xattr() ||
438 	    test_invalid_sqe())
439 		return EXIT_FAILURE;
440 
441 	return EXIT_SUCCESS;
442 }
443