@@ -206,6 +206,14 @@ static inline void io_uring_prep_rw(int op, struct io_uring_sqe *sqe, int fd,
sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
}
+static inline void io_uring_prep_readv_pi(struct io_uring_sqe *sqe, int fd,
+ const struct iovec *iovecs,
+ unsigned nr_vecs, off_t offset)
+{
+ io_uring_prep_rw(IORING_OP_READV_PI, sqe, fd, iovecs, nr_vecs, offset);
+}
+
+
static inline void io_uring_prep_readv(struct io_uring_sqe *sqe, int fd,
const struct iovec *iovecs,
unsigned nr_vecs, off_t offset)
@@ -228,6 +236,14 @@ static inline void io_uring_prep_writev(struct io_uring_sqe *sqe, int fd,
io_uring_prep_rw(IORING_OP_WRITEV, sqe, fd, iovecs, nr_vecs, offset);
}
+static inline void io_uring_prep_writev_pi(struct io_uring_sqe *sqe, int fd,
+ const struct iovec *iovecs,
+ unsigned nr_vecs, off_t offset)
+{
+ io_uring_prep_rw(IORING_OP_WRITEV_PI, sqe, fd, iovecs, nr_vecs, offset);
+}
+
+
static inline void io_uring_prep_write_fixed(struct io_uring_sqe *sqe, int fd,
const void *buf, unsigned nbytes,
off_t offset, int buf_index)
@@ -86,6 +86,8 @@ enum {
IORING_OP_NOP,
IORING_OP_READV,
IORING_OP_WRITEV,
+ IORING_OP_READV_PI,
+ IORING_OP_WRITEV_PI,
IORING_OP_FSYNC,
IORING_OP_READ_FIXED,
IORING_OP_WRITE_FIXED,
@@ -13,7 +13,7 @@ all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register
send_recvmsg a4c0b3decb33-test 500f9fbadef8-test timeout \
sq-space_left stdout cq-ready cq-peek-batch file-register \
cq-size 8a9973408177-test a0908ae19763-test 232c93d07b74-test \
- socket-rw accept timeout-overflow defer read-write io-cancel \
+ socket-rw accept timeout-overflow defer read-write pi_passthrough io-cancel \
link-timeout cq-overflow link_drain fc2a85cb02ef-test \
poll-link accept-link fixed-link poll-cancel-ton teardowns \
poll-many b5837bd5311d-test accept-test d77a67ed5f27-test \
@@ -40,7 +40,7 @@ test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \
500f9fbadef8-test.c timeout.c sq-space_left.c stdout.c cq-ready.c\
cq-peek-batch.c file-register.c cq-size.c 8a9973408177-test.c \
a0908ae19763-test.c 232c93d07b74-test.c socket-rw.c accept.c \
- timeout-overflow.c defer.c read-write.c io-cancel.c link-timeout.c \
+ timeout-overflow.c defer.c read-write.c pi_passthrough.c io-cancel.c link-timeout.c \
cq-overflow.c link_drain.c fc2a85cb02ef-test.c poll-link.c \
accept-link.c fixed-link.c poll-cancel-ton.c teardowns.c poll-many.c \
b5837bd5311d-test.c accept-test.c d77a67ed5f27-test.c connect.c \
new file mode 100644
@@ -0,0 +1,267 @@
+/*
+ * Simple app that demonstrates how to setup an io_uring interface,
+ * submit and complete IO against it, and then tear it down.
+ *
+ * gcc -Wall -O2 -D_GNU_SOURCE -o pi_passthrough pi_passthrough.c -luring
+ * modprobe scsi_debug.ko dif=1 guard=1 dev_size_mb=1024 num_parts=1 ato=1 dix=31
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include "liburing.h"
+
+#define NR_SECTOR 11
+#define SECTOR_SIZE 512
+#define BUF_SIZE (NR_SECTOR * SECTOR_SIZE)
+
+/* Will be round up power of 2 */
+#define QD (NR_SECTOR + 1 )
+
+struct sd_dif_tuple {
+ uint16_t guard_tag; /* Checksum */
+ uint16_t app_tag; /* Opaque storage */
+ uint32_t ref_tag; /* Target LBA or indirect LBA */
+};
+
+
+typedef unsigned short __sum16;
+static inline unsigned short from32to16(unsigned int x)
+{
+ /* add up 16-bit and 16-bit for 16+c bit */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up carry.. */
+ x = (x & 0xffff) + (x >> 16);
+ return x;
+}
+
+static unsigned int do_csum(const unsigned char *buff, int len)
+{
+ int odd, count;
+ unsigned long result = 0;
+
+ if (len <= 0)
+ goto out;
+ odd = 1 & (unsigned long) buff;
+ if (odd) {
+#ifdef __LITTLE_ENDIAN
+ result = *buff;
+#else
+ result += (*buff << 8);
+#endif
+ len--;
+ buff++;
+ }
+ count = len >> 1; /* nr of 16-bit words.. */
+ if (count) {
+ if (2 & (unsigned long) buff) {
+ result += *(unsigned short *) buff;
+ count--;
+ len -= 2;
+ buff += 2;
+ }
+ count >>= 1; /* nr of 32-bit words.. */
+ if (count) {
+ unsigned long carry = 0;
+ do {
+ unsigned long w = *(unsigned int *) buff;
+ count--;
+ buff += 4;
+ result += carry;
+ result += w;
+ carry = (w > result);
+ } while (count);
+ result += carry;
+ result = (result & 0xffff) + (result >> 16);
+ }
+ if (len & 2) {
+ result += *(unsigned short *) buff;
+ buff += 2;
+ }
+ }
+ if (len & 1)
+#ifdef __LITTLE_ENDIAN
+ result += *buff;
+#else
+ result += (*buff << 8);
+#endif
+ result = from32to16(result);
+ if (odd)
+ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+ return result;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+__sum16 ip_compute_csum(const void *buff, int len)
+{
+ return (__sum16)~do_csum(buff, len);
+}
+
+static void stamp_pi_buffer(struct sd_dif_tuple *t, uint16_t csum,
+ uint16_t tag, uint32_t sector)
+{
+ //t->guard_tag = htons(csum);
+ t->guard_tag = csum;
+ t->app_tag = getpid();
+ t->ref_tag = htonl(sector);
+}
+
+static void dump_buffer(char *buf, size_t len)
+{
+ size_t off;
+ char *p;
+
+ for (p = buf; p < buf + len; p++) {
+ off = p - buf;
+ if (off % 32 == 0) {
+ if (p != buf)
+ printf("\n");
+ printf("%05zu:", off);
+ }
+ printf(" %02x", *p & 0xFF);
+ }
+ printf("\n");
+}
+
+int io_rw(int fd, int write, void *buf, size_t len,
+ void *mbuf, size_t pi_buflen)
+{
+ struct io_uring ring;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct iovec *iovecs;
+ int i, ret, pending, done, offset=0;
+
+ iovecs = calloc(QD, sizeof(struct iovec));
+ for (i = 0; i < QD - 1; i++) {
+ iovecs[i].iov_base = buf + i * SECTOR_SIZE;
+ iovecs[i].iov_len = SECTOR_SIZE;
+ }
+ /* Last iovecs store protect information */
+ iovecs[i].iov_base = mbuf;
+ iovecs[i].iov_len = pi_buflen;
+
+ if (write) {
+ __sum16 ip_csum;
+ int out_fd = 0;
+ out_fd = open("/dev/random", O_RDONLY);
+ if (out_fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ ret = read(out_fd, buf, len);
+ printf("read %d bytes from file\n", ret);
+ for( i = 0; i < NR_SECTOR; i++) {
+ ip_csum = ip_compute_csum(buf + i*SECTOR_SIZE, SECTOR_SIZE);
+ printf("ip_csum:0x%x\n", ip_csum);
+
+ stamp_pi_buffer(mbuf + i * sizeof(struct sd_dif_tuple),
+ ip_csum,0x0, i & 0xffffffff);
+ }
+ }
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret < 0) {
+ fprintf(stderr, "queue_init: %s\n", strerror(-ret));
+ return 1;
+ }
+
+ sqe = io_uring_get_sqe(&ring);
+ if (!sqe)
+ return 1;
+ if(write)
+ io_uring_prep_writev_pi(sqe, fd, iovecs, QD, offset);
+ else
+ io_uring_prep_readv_pi(sqe, fd, iovecs, QD, offset);
+
+ ret = io_uring_submit(&ring);
+ if (ret < 0) {
+ fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret));
+ return 1;
+ }
+
+ done = 0;
+ pending = ret;
+ for (i = 0; i < pending; i++) {
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret < 0) {
+ fprintf(stderr, "io_uring_wait_cqe: %s\n", strerror(-ret));
+ return 1;
+ }
+
+ done++;
+ ret = 0;
+ if (cqe->res != SECTOR_SIZE) {
+ fprintf(stderr, "ceq->res=%d, wanted %d\n",
+ cqe->res, SECTOR_SIZE);
+ ret = 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+ if (ret)
+ break;
+ }
+ io_uring_queue_exit(&ring);
+ printf("Submitted=%d, completed=%d\n", pending, done);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int page_size = 4096;
+ size_t pi_buflen;
+ void *buf, *mbuf;
+ void *buf2, *mbuf2; //read back
+
+ if (argc < 2) {
+ printf("%s: file\n", argv[0]);
+ return 1;
+ }
+
+ fd = open(argv[1], O_RDWR |O_SYNC| O_DIRECT);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ /* write with protect information */
+ pi_buflen = NR_SECTOR * sizeof(struct sd_dif_tuple);
+ if (posix_memalign(&buf, page_size, BUF_SIZE) ||
+ posix_memalign(&mbuf, page_size, pi_buflen) ) {
+ perror("memalign");
+ return 1;
+ }
+ io_rw(fd, 1, buf, BUF_SIZE, mbuf, pi_buflen);
+
+ /* read out protect information */
+ if (posix_memalign(&buf2, page_size, BUF_SIZE) ||
+ posix_memalign(&mbuf2, page_size, pi_buflen) ) {
+ perror("memalign");
+ return 1;
+ }
+ io_rw(fd, 0, buf2, BUF_SIZE, mbuf2, pi_buflen);
+ close(fd);
+
+ /* Compare result. */
+ if(memcmp(buf, buf2, BUF_SIZE)) {
+ printf("err!! protect date mismatch!!\n");
+ dump_buffer(buf, BUF_SIZE);
+ dump_buffer(mbuf, pi_buflen);
+ }
+ if(memcmp(mbuf, mbuf2, pi_buflen)) {
+ printf("err!! protect date mismatch!!\n");
+ dump_buffer(buf2, BUF_SIZE);
+ dump_buffer(mbuf2, pi_buflen);
+ }
+ printf("test succ!!\n");
+
+ return 0;
+}
Demonstrate how to use IORING_OP_READ{WRITE}V_PI cmd. Write data together with protection information, then read back and compare results. Signed-off-by: Bob Liu <bob.liu@oracle.com> --- src/include/liburing.h | 16 ++ src/include/liburing/io_uring.h | 2 + test/Makefile | 4 +- test/pi_passthrough.c | 267 ++++++++++++++++++++++++++++++++ 4 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 test/pi_passthrough.c