mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
fsstress: add IO_URING read and write operations
IO_URING is a new feature of curent linux kernel, add basic IO_URING read/write into fsstess to cover this kind of IO testing. Signed-off-by: Zorro Lang <zlang@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
@@ -8,13 +8,13 @@ _______________________
|
||||
sudo apt-get install xfslibs-dev uuid-dev libtool-bin \
|
||||
e2fsprogs automake gcc libuuid1 quota attr libattr1-dev make \
|
||||
libacl1-dev libaio-dev xfsprogs libgdbm-dev gawk fio dbench \
|
||||
uuid-runtime python sqlite3
|
||||
uuid-runtime python sqlite3 liburing-dev
|
||||
For Fedora, RHEL, or CentOS:
|
||||
yum install acl attr automake bc dbench dump e2fsprogs fio \
|
||||
gawk gcc indent libtool lvm2 make psmisc quota sed \
|
||||
xfsdump xfsprogs \
|
||||
libacl-devel libattr-devel libaio-devel libuuid-devel \
|
||||
xfsprogs-devel btrfs-progs-devel python sqlite
|
||||
xfsprogs-devel btrfs-progs-devel python sqlite liburing-devel
|
||||
(Older distributions may require xfsprogs-qa-devel as well.)
|
||||
(Note that for RHEL and CentOS, you may need the EPEL repo.)
|
||||
- run make
|
||||
|
||||
@@ -61,6 +61,7 @@ AC_PACKAGE_NEED_ACLINIT_LIBACL
|
||||
|
||||
AC_PACKAGE_WANT_GDBM
|
||||
AC_PACKAGE_WANT_AIO
|
||||
AC_PACKAGE_WANT_URING
|
||||
AC_PACKAGE_WANT_DMAPI
|
||||
AC_PACKAGE_WANT_LINUX_FIEMAP_H
|
||||
AC_PACKAGE_WANT_FALLOCATE
|
||||
|
||||
@@ -61,6 +61,7 @@ RPM_VERSION = @rpm_version@
|
||||
ENABLE_SHARED = @enable_shared@
|
||||
HAVE_DB = @have_db@
|
||||
HAVE_AIO = @have_aio@
|
||||
HAVE_URING = @have_uring@
|
||||
HAVE_FALLOCATE = @have_fallocate@
|
||||
HAVE_OPEN_BY_HANDLE_AT = @have_open_by_handle_at@
|
||||
HAVE_DMAPI = @have_dmapi@
|
||||
|
||||
@@ -24,6 +24,11 @@ LCFLAGS += -DAIO
|
||||
LLDLIBS += -laio -lpthread
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_URING), true)
|
||||
LCFLAGS += -DURING
|
||||
LLDLIBS += -luring
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_LIBBTRFSUTIL), true)
|
||||
LLDLIBS += -lbtrfsutil
|
||||
endif
|
||||
|
||||
+138
-1
@@ -30,6 +30,11 @@
|
||||
#include <libaio.h>
|
||||
io_context_t io_ctx;
|
||||
#endif
|
||||
#ifdef URING
|
||||
#include <liburing.h>
|
||||
#define URING_ENTRIES 1
|
||||
struct io_uring ring;
|
||||
#endif
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
@@ -139,6 +144,8 @@ typedef enum {
|
||||
OP_TRUNCATE,
|
||||
OP_UNLINK,
|
||||
OP_UNRESVSP,
|
||||
OP_URING_READ,
|
||||
OP_URING_WRITE,
|
||||
OP_WRITE,
|
||||
OP_WRITEV,
|
||||
OP_LAST
|
||||
@@ -267,6 +274,8 @@ void sync_f(int, long);
|
||||
void truncate_f(int, long);
|
||||
void unlink_f(int, long);
|
||||
void unresvsp_f(int, long);
|
||||
void uring_read_f(int, long);
|
||||
void uring_write_f(int, long);
|
||||
void write_f(int, long);
|
||||
void writev_f(int, long);
|
||||
char *xattr_flag_to_string(int);
|
||||
@@ -335,6 +344,8 @@ opdesc_t ops[] = {
|
||||
{ OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
|
||||
{ OP_UNLINK, "unlink", unlink_f, 1, 1 },
|
||||
{ OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
|
||||
{ OP_URING_READ, "uring_read", uring_read_f, 1, 0 },
|
||||
{ OP_URING_WRITE, "uring_write", uring_write_f, 1, 1 },
|
||||
{ OP_WRITE, "write", write_f, 4, 1 },
|
||||
{ OP_WRITEV, "writev", writev_f, 4, 1 },
|
||||
}, *ops_end;
|
||||
@@ -692,6 +703,12 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "io_setup failed");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
#ifdef URING
|
||||
if (io_uring_queue_init(URING_ENTRIES, &ring, 0)) {
|
||||
fprintf(stderr, "io_uring_queue_init failed\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; !loops || (i < loops); i++)
|
||||
doproc();
|
||||
@@ -701,7 +718,9 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef URING
|
||||
io_uring_queue_exit(&ring);
|
||||
#endif
|
||||
cleanup_flist();
|
||||
free(freq_table);
|
||||
return 0;
|
||||
@@ -2170,6 +2189,108 @@ do_aio_rw(int opno, long r, int flags)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef URING
|
||||
void
|
||||
do_uring_rw(int opno, long r, int flags)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int e;
|
||||
pathname_t f;
|
||||
int fd = -1;
|
||||
size_t len;
|
||||
int64_t lr;
|
||||
off64_t off;
|
||||
struct stat64 stb;
|
||||
int v;
|
||||
char st[1024];
|
||||
struct io_uring_sqe *sqe;
|
||||
struct io_uring_cqe *cqe;
|
||||
struct iovec iovec;
|
||||
int iswrite = (flags & (O_WRONLY | O_RDWR)) ? 1 : 0;
|
||||
|
||||
init_pathname(&f);
|
||||
if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
|
||||
if (v)
|
||||
printf("%d/%d: do_uring_rw - no filename\n", procid, opno);
|
||||
goto uring_out;
|
||||
}
|
||||
fd = open_path(&f, flags);
|
||||
e = fd < 0 ? errno : 0;
|
||||
check_cwd();
|
||||
if (fd < 0) {
|
||||
if (v)
|
||||
printf("%d/%d: do_uring_rw - open %s failed %d\n",
|
||||
procid, opno, f.path, e);
|
||||
goto uring_out;
|
||||
}
|
||||
if (fstat64(fd, &stb) < 0) {
|
||||
if (v)
|
||||
printf("%d/%d: do_uring_rw - fstat64 %s failed %d\n",
|
||||
procid, opno, f.path, errno);
|
||||
goto uring_out;
|
||||
}
|
||||
inode_info(st, sizeof(st), &stb, v);
|
||||
if (!iswrite && stb.st_size == 0) {
|
||||
if (v)
|
||||
printf("%d/%d: do_uring_rw - %s%s zero size\n", procid, opno,
|
||||
f.path, st);
|
||||
goto uring_out;
|
||||
}
|
||||
sqe = io_uring_get_sqe(&ring);
|
||||
if (!sqe) {
|
||||
if (v)
|
||||
printf("%d/%d: do_uring_rw - io_uring_get_sqe failed\n",
|
||||
procid, opno);
|
||||
goto uring_out;
|
||||
}
|
||||
lr = ((int64_t)random() << 32) + random();
|
||||
len = (random() % FILELEN_MAX) + 1;
|
||||
buf = malloc(len);
|
||||
if (!buf) {
|
||||
if (v)
|
||||
printf("%d/%d: do_uring_rw - malloc failed\n",
|
||||
procid, opno);
|
||||
goto uring_out;
|
||||
}
|
||||
iovec.iov_base = buf;
|
||||
iovec.iov_len = len;
|
||||
if (iswrite) {
|
||||
off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
|
||||
off %= maxfsize;
|
||||
memset(buf, nameseq & 0xff, len);
|
||||
io_uring_prep_writev(sqe, fd, &iovec, 1, off);
|
||||
} else {
|
||||
off = (off64_t)(lr % stb.st_size);
|
||||
io_uring_prep_readv(sqe, fd, &iovec, 1, off);
|
||||
}
|
||||
|
||||
if ((e = io_uring_submit_and_wait(&ring, 1)) != 1) {
|
||||
if (v)
|
||||
printf("%d/%d: %s - io_uring_submit failed %d\n", procid, opno,
|
||||
iswrite ? "uring_write" : "uring_read", e);
|
||||
goto uring_out;
|
||||
}
|
||||
if ((e = io_uring_wait_cqe(&ring, &cqe)) < 0) {
|
||||
if (v)
|
||||
printf("%d/%d: %s - io_uring_wait_cqe failed %d\n", procid, opno,
|
||||
iswrite ? "uring_write" : "uring_read", e);
|
||||
goto uring_out;
|
||||
}
|
||||
if (v)
|
||||
printf("%d/%d: %s %s%s [%lld, %d(res=%d)] %d\n",
|
||||
procid, opno, iswrite ? "uring_write" : "uring_read",
|
||||
f.path, st, (long long)off, (int)len, cqe->res, e);
|
||||
io_uring_cqe_seen(&ring, cqe);
|
||||
|
||||
uring_out:
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
free_pathname(&f);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
aread_f(int opno, long r)
|
||||
{
|
||||
@@ -5044,6 +5165,22 @@ unresvsp_f(int opno, long r)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
uring_read_f(int opno, long r)
|
||||
{
|
||||
#ifdef URING
|
||||
do_uring_rw(opno, r, O_RDONLY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
uring_write_f(int opno, long r)
|
||||
{
|
||||
#ifdef URING
|
||||
do_uring_rw(opno, r, O_WRONLY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
write_f(int opno, long r)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ LSRCFILES = \
|
||||
package_dmapidev.m4 \
|
||||
package_globals.m4 \
|
||||
package_libcdev.m4 \
|
||||
package_liburing.m4 \
|
||||
package_ncurses.m4 \
|
||||
package_pthread.m4 \
|
||||
package_ssldev.m4 \
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
AC_DEFUN([AC_PACKAGE_WANT_URING],
|
||||
[ AC_CHECK_HEADERS(liburing.h, [ have_uring=true ], [ have_uring=false ])
|
||||
AC_SUBST(have_uring)
|
||||
])
|
||||
Reference in New Issue
Block a user