Skip to content

Commit c7ca761

Browse files
committed
test: add async test case
Add tests cases for the async submission API. Since there is no easy way to tests async test, it only tests the fallback mode, when there is no io_uring. Signed-off-by: Daniel Wagner <wagi@kernel.org>
1 parent daa9852 commit c7ca761

2 files changed

Lines changed: 170 additions & 0 deletions

File tree

libnvme/test/ioctl/async.c

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
/**
3+
* This file is part of libnvme.
4+
* Copyright (c) 2026 Daniel Wagner, SUSE Software Solutions
5+
*/
6+
7+
#include <errno.h>
8+
#include <stdint.h>
9+
#include <stdio.h>
10+
11+
#include <libnvme.h>
12+
13+
#include "mock.h"
14+
#include "util.h"
15+
16+
static struct libnvme_transport_handle *test_hdl;
17+
18+
static void test_admin_async_submit_not_supported(void)
19+
{
20+
struct nvme_id_ctrl id = {};
21+
struct libnvme_passthru_cmd cmd;
22+
int err;
23+
24+
nvme_init_identify_ctrl(&cmd, &id);
25+
err = libnvme_submit_admin_passthru_async(test_hdl, &cmd,
26+
(void *)(uintptr_t)0x1234);
27+
check(err == -ENOTSUP, "submit async returned %d, expected %d",
28+
err, -ENOTSUP);
29+
}
30+
31+
static void test_io_async_submit_not_supported(void)
32+
{
33+
struct libnvme_passthru_cmd cmd = {};
34+
int err;
35+
36+
err = libnvme_submit_io_passthru_async(test_hdl, &cmd,
37+
(void *)(uintptr_t)0x5678);
38+
check(err == -ENOTSUP, "IO submit async returned %d, expected %d",
39+
err, -ENOTSUP);
40+
}
41+
42+
static void test_async_reap_not_supported(void)
43+
{
44+
struct libnvme_passthru_completion completion = {};
45+
int err;
46+
47+
err = libnvme_reap_passthru_async(test_hdl, &completion);
48+
check(err == -ENOTSUP, "reap async returned %d, expected %d",
49+
err, -ENOTSUP);
50+
}
51+
52+
static void test_sync_path_fallback(void)
53+
{
54+
struct nvme_id_ctrl expected_id = {}, id = {};
55+
struct mock_cmd mock_admin_cmd = {
56+
.opcode = nvme_admin_identify,
57+
.data_len = sizeof(expected_id),
58+
.cdw10 = NVME_IDENTIFY_CNS_CTRL,
59+
.out_data = &expected_id,
60+
};
61+
struct libnvme_passthru_cmd cmd;
62+
int err;
63+
64+
arbitrary(&expected_id, sizeof(expected_id));
65+
set_mock_admin_cmds(&mock_admin_cmd, 1);
66+
nvme_init_identify_ctrl(&cmd, &id);
67+
err = libnvme_exec_admin_passthru(test_hdl, &cmd);
68+
end_mock_cmds();
69+
check(err == 0, "sync fallback returned %d", err);
70+
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
71+
}
72+
73+
static void test_io_sync_path_fallback(void)
74+
{
75+
struct libnvme_passthru_cmd cmd = {};
76+
struct mock_cmd mock_io_cmd = {
77+
.opcode = nvme_cmd_read,
78+
.data_len = 0,
79+
};
80+
int err;
81+
82+
set_mock_io_cmds(&mock_io_cmd, 1);
83+
cmd.opcode = nvme_cmd_read;
84+
err = libnvme_exec_io_passthru(test_hdl, &cmd);
85+
end_mock_cmds();
86+
check(err == 0, "IO sync fallback returned %d", err);
87+
}
88+
89+
static void test_batched_submit_wait_pattern(void)
90+
{
91+
struct nvme_id_ctrl id1 = {}, id2 = {};
92+
struct mock_cmd mock_cmds[] = {
93+
{
94+
.opcode = nvme_admin_identify,
95+
.data_len = sizeof(id1),
96+
.cdw10 = NVME_IDENTIFY_CNS_CTRL,
97+
.out_data = &id1,
98+
},
99+
{
100+
.opcode = nvme_admin_identify,
101+
.data_len = sizeof(id2),
102+
.cdw10 = NVME_IDENTIFY_CNS_CTRL,
103+
.out_data = &id2,
104+
},
105+
};
106+
struct libnvme_passthru_cmd cmd1, cmd2;
107+
int err;
108+
109+
/* Test the batching pattern: submit multiple, then wait */
110+
arbitrary(&id1, sizeof(id1));
111+
arbitrary(&id2, sizeof(id2));
112+
set_mock_admin_cmds(mock_cmds, 2);
113+
114+
nvme_init_identify_ctrl(&cmd1, &id1);
115+
nvme_init_identify_ctrl(&cmd2, &id2);
116+
117+
/* When io_uring is unavailable, submit falls back to exec */
118+
err = libnvme_submit_admin_passthru(test_hdl, &cmd1);
119+
check(err == 0, "batched submit 1 returned %d", err);
120+
121+
err = libnvme_submit_admin_passthru(test_hdl, &cmd2);
122+
check(err == 0, "batched submit 2 returned %d", err);
123+
124+
/* wait is a no-op when io_uring is not available */
125+
err = libnvme_wait_passthru(test_hdl);
126+
check(err == -ENOTSUP, "batched wait returned %d", err);
127+
128+
end_mock_cmds();
129+
}
130+
131+
static void run_test(const char *test_name, void (*test_fn)(void))
132+
{
133+
printf("Running test %s...", test_name);
134+
fflush(stdout);
135+
test_fn();
136+
puts(" OK");
137+
}
138+
139+
#define RUN_TEST(name) run_test(#name, test_ ## name)
140+
141+
int main(void)
142+
{
143+
struct libnvme_global_ctx *ctx =
144+
libnvme_create_global_ctx(stdout, LIBNVME_DEFAULT_LOGLEVEL);
145+
146+
set_mock_fd(LIBNVME_TEST_FD);
147+
check(!libnvme_open(ctx, "NVME_TEST_FD", &test_hdl),
148+
"opening test link failed");
149+
150+
RUN_TEST(admin_async_submit_not_supported);
151+
RUN_TEST(io_async_submit_not_supported);
152+
RUN_TEST(async_reap_not_supported);
153+
RUN_TEST(sync_path_fallback);
154+
RUN_TEST(io_sync_path_fallback);
155+
RUN_TEST(batched_submit_wait_pattern);
156+
157+
libnvme_free_global_ctx(ctx);
158+
}

libnvme/test/ioctl/meson.build

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ ana = executable(
5252
)
5353
test('libnvme - ana', ana, env: mock_ioctl_env)
5454

55+
async = executable(
56+
'test-async',
57+
'async.c',
58+
dependencies: [
59+
config_dep,
60+
ccan_dep,
61+
libnvme_dep,
62+
],
63+
link_with: mock_ioctl,
64+
)
65+
test('libnvme - async', async, env: mock_ioctl_env)
66+
5567
if want_fabrics
5668
discovery = executable(
5769
'test-discovery',

0 commit comments

Comments
 (0)