接上文

代码流程

  1. 创建文件,大小(128*1024),内容使用0xaa填充。默认文件名”.basic-rw”,也可通过argv[1]指定。
  2. 创建buffer,分32个块,还个块2096大小。总大小与上面文件大小相同。 posix_memalign预对齐内存分配函数。
  3. has_nonvec_read函数通过调用 io_uring_setup 和 io_uring_register(IORING_REGISTER_PROBE) 来探查是否支持Vec操作。
  4. test_io主测试函数



!buffered sqthread fixed !nonvec
读写文件直接操作IO      
open() flags |= O_DIRECT; io_uring_queue_init() flags = IORING_SETUP_SQPOLL; io_uring_register_buffers(); io_uring_prep_readv();
  io_uring_register_files; io_uring_prep_write_fixed();  
  use_fd = 0;    



static int test_io(const char *file, int write, int buffered, int sqthread,
		   int fixed, int mixed_fixed, int nonvec)
{
	struct io_uring ring;
	int ret, ring_flags;

	if (sqthread) {
		if (geteuid()) {
			if (!warned) {
				fprintf(stderr, "SQPOLL requires root, skipping\n");
				warned = 1;
			}
			return 0;
		}
		ring_flags = IORING_SETUP_SQPOLL;
	} else {
		ring_flags = 0;
	}

	ret = io_uring_queue_init(64, &ring, ring_flags);
	if (ret) {
		fprintf(stderr, "ring create failed: %d\n", ret);
		return 1;
	}

	ret = __test_io(file, &ring, write, buffered, sqthread, fixed,
			mixed_fixed, nonvec, 0, 0, BS);

	io_uring_queue_exit(&ring);
	return ret;
}

static int __test_io(const char *file, struct io_uring *ring, int write, int buffered,
		     int sqthread, int fixed, int mixed_fixed, int nonvec,
		     int buf_select, int seq, int exp_len)
{
	struct io_uring_sqe *sqe;
	struct io_uring_cqe *cqe;
	int open_flags;
	int i, fd, ret;
	off_t offset;

#ifdef VERBOSE
	fprintf(stdout, "%s: start %d/%d/%d/%d/%d/%d: ", __FUNCTION__, write,
							buffered, sqthread,
							fixed, mixed_fixed,
							nonvec);
#endif
	if (sqthread && geteuid()) {
#ifdef VERBOSE
		fprintf(stdout, "SKIPPED (not root)\n");
#endif
		return 0;
	}

	if (write)
		open_flags = O_WRONLY;
	else
		open_flags = O_RDONLY;
	if (!buffered)
		open_flags |= O_DIRECT; //!无缓冲直接操作IO

	fd = open(file, open_flags);
	if (fd < 0) {
		perror("file open");
		goto err;
	}

	if (fixed) {
		ret = io_uring_register_buffers(ring, vecs, BUFFERS);
		if (ret) {
			fprintf(stderr, "buffer reg failed: %d\n", ret);
			goto err;
		}
	}
	if (sqthread) {
		ret = io_uring_register_files(ring, &fd, 1);
		if (ret) {
			fprintf(stderr, "file reg failed: %d\n", ret);
			goto err;
		}
	}

	offset = 0;
	for (i = 0; i < BUFFERS; i++) {
		sqe = io_uring_get_sqe(ring);
		if (!sqe) {
			fprintf(stderr, "sqe get failed\n");
			goto err;
		}
		if (!seq)
			offset = BS * (rand() % BUFFERS);
		if (write) {
			int do_fixed = fixed;
			int use_fd = fd;

			if (sqthread)
				use_fd = 0;
			if (fixed && (i & 1))
				do_fixed = 0;
			if (do_fixed) {
				io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
								vecs[i].iov_len,
								offset, i);
			} else if (nonvec) {
				io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
							vecs[i].iov_len, offset);
			} else {
				io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
								offset);
			}
		} else {
			int do_fixed = fixed;
			int use_fd = fd;

			if (sqthread)
				use_fd = 0;
			if (fixed && (i & 1))
				do_fixed = 0;
			if (do_fixed) {
				io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
								vecs[i].iov_len,
								offset, i);
			} else if (nonvec) {
				io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
							vecs[i].iov_len, offset);
			} else {
				io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
								offset);
			}

		}
		if (sqthread)
			sqe->flags |= IOSQE_FIXED_FILE;
		if (buf_select) {
			if (nonvec)
				sqe->addr = 0;
			sqe->flags |= IOSQE_BUFFER_SELECT;
			sqe->buf_group = buf_select;
			sqe->user_data = i;
		}
		if (seq)
			offset += BS;
	}

	ret = io_uring_submit(ring);
	if (ret != BUFFERS) {
		fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
		goto err;
	}

	for (i = 0; i < BUFFERS; i++) {
		ret = io_uring_wait_cqe(ring, &cqe);
		if (ret) {
			fprintf(stderr, "wait_cqe=%d\n", ret);
			goto err;
		}
		if (cqe->res == -EINVAL && nonvec) {
			if (!warned) {
				fprintf(stdout, "Non-vectored IO not "
					"supported, skipping\n");
				warned = 1;
				no_read = 1;
			}
		} else if (cqe->res != exp_len) {
			fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, exp_len);
			goto err;
		}
		if (buf_select && exp_len == BS) {
			int bid = cqe->flags >> 16;
			unsigned char *ptr = vecs[bid].iov_base;
			int j;

			for (j = 0; j < BS; j++) {
				if (ptr[j] == cqe->user_data)
					continue;

				fprintf(stderr, "Data mismatch! bid=%d, "
						"wanted=%d, got=%d\n", bid,
						(int)cqe->user_data, ptr[j]);
				return 1;
			}
		}
		io_uring_cqe_seen(ring, cqe);
	}

	if (fixed) {
		ret = io_uring_unregister_buffers(ring);
		if (ret) {
			fprintf(stderr, "buffer unreg failed: %d\n", ret);
			goto err;
		}
	}
	if (sqthread) {
		ret = io_uring_unregister_files(ring);
		if (ret) {
			fprintf(stderr, "file unreg failed: %d\n", ret);
			goto err;
		}
	}

	close(fd);
#ifdef VERBOSE
	fprintf(stdout, "PASS\n");
#endif
	return 0;
err:
#ifdef VERBOSE
	fprintf(stderr, "FAILED\n");
#endif
	if (fd != -1)
		close(fd);
	return 1;
}
$ sudo ./test/read-write
__test_io: start 0/0/0/0/0/0: PASS
__test_io: start 1/0/0/0/0/0: PASS
__test_io: start 0/1/0/0/0/0: PASS
__test_io: start 1/1/0/0/0/0: PASS
__test_io: start 0/0/1/0/0/0: PASS
__test_io: start 1/0/1/0/0/0: PASS
__test_io: start 0/1/1/0/0/0: PASS
__test_io: start 1/1/1/0/0/0: PASS
__test_io: start 0/0/0/1/0/0: PASS
__test_io: start 1/0/0/1/0/0: PASS
__test_io: start 0/1/0/1/0/0: PASS
__test_io: start 1/1/0/1/0/0: PASS
__test_io: start 0/0/1/1/0/0: PASS
__test_io: start 1/0/1/1/0/0: PASS
__test_io: start 0/1/1/1/0/0: PASS
__test_io: start 1/1/1/1/0/0: PASS
__test_io: start 0/0/0/0/1/0: PASS
__test_io: start 1/0/0/0/1/0: PASS
__test_io: start 0/1/0/0/1/0: PASS
__test_io: start 1/1/0/0/1/0: PASS
__test_io: start 0/0/1/0/1/0: PASS
__test_io: start 1/0/1/0/1/0: PASS
__test_io: start 0/1/1/0/1/0: PASS
__test_io: start 1/1/1/0/1/0: PASS
__test_io: start 0/0/0/1/1/0: PASS
__test_io: start 1/0/0/1/1/0: PASS
__test_io: start 0/1/0/1/1/0: PASS
__test_io: start 1/1/0/1/1/0: PASS
__test_io: start 0/0/1/1/1/0: PASS
__test_io: start 1/0/1/1/1/0: PASS
__test_io: start 0/1/1/1/1/0: PASS
__test_io: start 1/1/1/1/1/0: PASS
__test_io: start 0/0/0/0/0/1: PASS
__test_io: start 1/0/0/0/0/1: PASS
__test_io: start 0/1/0/0/0/1: PASS
__test_io: start 1/1/0/0/0/1: PASS
__test_io: start 0/0/1/0/0/1: PASS
__test_io: start 1/0/1/0/0/1: PASS
__test_io: start 0/1/1/0/0/1: PASS
__test_io: start 1/1/1/0/0/1: PASS
__test_io: start 0/0/0/1/0/1: PASS
__test_io: start 1/0/0/1/0/1: PASS
__test_io: start 0/1/0/1/0/1: PASS
__test_io: start 1/1/0/1/0/1: PASS
__test_io: start 0/0/1/1/0/1: PASS
__test_io: start 1/0/1/1/0/1: PASS
__test_io: start 0/1/1/1/0/1: PASS
__test_io: start 1/1/1/1/0/1: PASS
__test_io: start 0/0/0/0/1/1: PASS
__test_io: start 1/0/0/0/1/1: PASS
__test_io: start 0/1/0/0/1/1: PASS
__test_io: start 1/1/0/0/1/1: PASS
__test_io: start 0/0/1/0/1/1: PASS
__test_io: start 1/0/1/0/1/1: PASS
__test_io: start 0/1/1/0/1/1: PASS
__test_io: start 1/1/1/0/1/1: PASS
__test_io: start 0/0/0/1/1/1: PASS
__test_io: start 1/0/0/1/1/1: PASS
__test_io: start 0/1/0/1/1/1: PASS
__test_io: start 1/1/0/1/1/1: PASS
__test_io: start 0/0/1/1/1/1: PASS
__test_io: start 1/0/1/1/1/1: PASS
__test_io: start 0/1/1/1/1/1: PASS
__test_io: start 1/1/1/1/1/1: PASS

__test_io: start 1/0/0/0/0/0: PASS
__test_io: start 0/0/0/0/0/1: PASS
__test_io: start 1/0/0/0/0/0: PASS
__test_io: start 0/0/0/0/0/0: PASS
__test_io: start 0/0/0/0/0/1: PASS
__test_io: start 0/0/0/0/0/0: PASS