Skip to content

Commit 9b2785e

Browse files
Ming Leiaxboe
authored andcommitted
ublk selftests: add --no_ublk_fixed_fd for not using registered ublk char device
Add a new command line option --no_ublk_fixed_fd that excludes the ublk control device (/dev/ublkcN) from io_uring's registered files array. When this option is used, only backing files are registered starting from index 1, while the ublk control device is accessed using its raw file descriptor. Add ublk_get_registered_fd() helper function that returns the appropriate file descriptor for use with io_uring operations. Key optimizations implemented: - Cache UBLKS_Q_NO_UBLK_FIXED_FD flag in ublk_queue.flags to avoid reading dev->no_ublk_fixed_fd in fast path - Cache ublk char device fd in ublk_queue.ublk_fd for fast access - Update ublk_get_registered_fd() to use ublk_queue * parameter - Update io_uring_prep_buf_register/unregister() to use ublk_queue * - Replace ublk_device * access with ublk_queue * access in fast paths Also pass --no_ublk_fixed_fd to test_stress_04.sh for covering plain ublk char device mode. Signed-off-by: Ming Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent c5c5eb2 commit 9b2785e

File tree

6 files changed

+74
-33
lines changed

6 files changed

+74
-33
lines changed

tools/testing/selftests/ublk/file_backed.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static int loop_queue_flush_io(struct ublk_thread *t, struct ublk_queue *q,
2020
struct io_uring_sqe *sqe[1];
2121

2222
ublk_io_alloc_sqes(t, sqe, 1);
23-
io_uring_prep_fsync(sqe[0], 1 /*fds[1]*/, IORING_FSYNC_DATASYNC);
23+
io_uring_prep_fsync(sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/, IORING_FSYNC_DATASYNC);
2424
io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE);
2525
/* bit63 marks us as tgt io */
2626
sqe[0]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1);
@@ -42,7 +42,7 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q,
4242
if (!sqe[0])
4343
return -ENOMEM;
4444

45-
io_uring_prep_rw(op, sqe[0], 1 /*fds[1]*/,
45+
io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/,
4646
addr,
4747
iod->nr_sectors << 9,
4848
iod->start_sector << 9);
@@ -56,19 +56,19 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q,
5656

5757
ublk_io_alloc_sqes(t, sqe, 3);
5858

59-
io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
59+
io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
6060
sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK;
6161
sqe[0]->user_data = build_user_data(tag,
6262
ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1);
6363

64-
io_uring_prep_rw(op, sqe[1], 1 /*fds[1]*/, 0,
64+
io_uring_prep_rw(op, sqe[1], ublk_get_registered_fd(q, 1) /*fds[1]*/, 0,
6565
iod->nr_sectors << 9,
6666
iod->start_sector << 9);
6767
sqe[1]->buf_index = tag;
6868
sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK;
6969
sqe[1]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1);
7070

71-
io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
71+
io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
7272
sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1);
7373

7474
return 2;

tools/testing/selftests/ublk/kublk.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ static void ublk_thread_deinit(struct ublk_thread *t)
432432
}
433433
}
434434

435-
static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags)
435+
static int ublk_queue_init(struct ublk_queue *q, unsigned long long extra_flags)
436436
{
437437
struct ublk_dev *dev = q->dev;
438438
int depth = dev->dev_info.queue_depth;
@@ -446,6 +446,9 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags)
446446
q->flags = dev->dev_info.flags;
447447
q->flags |= extra_flags;
448448

449+
/* Cache fd in queue for fast path access */
450+
q->ublk_fd = dev->fds[0];
451+
449452
cmd_buf_size = ublk_queue_cmd_buf_sz(q);
450453
off = UBLKSRV_CMD_BUF_OFFSET + q->q_id * ublk_queue_max_cmd_buf_sz();
451454
q->io_cmd_buf = mmap(0, cmd_buf_size, PROT_READ,
@@ -481,9 +484,10 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags)
481484
return -ENOMEM;
482485
}
483486

484-
static int ublk_thread_init(struct ublk_thread *t)
487+
static int ublk_thread_init(struct ublk_thread *t, unsigned long long extra_flags)
485488
{
486489
struct ublk_dev *dev = t->dev;
490+
unsigned long long flags = dev->dev_info.flags | extra_flags;
487491
int ring_depth = dev->tgt.sq_depth, cq_depth = dev->tgt.cq_depth;
488492
int ret;
489493

@@ -512,7 +516,17 @@ static int ublk_thread_init(struct ublk_thread *t)
512516

513517
io_uring_register_ring_fd(&t->ring);
514518

515-
ret = io_uring_register_files(&t->ring, dev->fds, dev->nr_fds);
519+
if (flags & UBLKS_Q_NO_UBLK_FIXED_FD) {
520+
/* Register only backing files starting from index 1, exclude ublk control device */
521+
if (dev->nr_fds > 1) {
522+
ret = io_uring_register_files(&t->ring, &dev->fds[1], dev->nr_fds - 1);
523+
} else {
524+
/* No backing files to register, skip file registration */
525+
ret = 0;
526+
}
527+
} else {
528+
ret = io_uring_register_files(&t->ring, dev->fds, dev->nr_fds);
529+
}
516530
if (ret) {
517531
ublk_err("ublk dev %d thread %d register files failed %d\n",
518532
t->dev->dev_info.dev_id, t->idx, ret);
@@ -626,9 +640,12 @@ int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io)
626640

627641
/* These fields should be written once, never change */
628642
ublk_set_sqe_cmd_op(sqe[0], cmd_op);
629-
sqe[0]->fd = 0; /* dev->fds[0] */
643+
sqe[0]->fd = ublk_get_registered_fd(q, 0); /* dev->fds[0] */
630644
sqe[0]->opcode = IORING_OP_URING_CMD;
631-
sqe[0]->flags = IOSQE_FIXED_FILE;
645+
if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD)
646+
sqe[0]->flags = 0; /* Use raw FD, not fixed file */
647+
else
648+
sqe[0]->flags = IOSQE_FIXED_FILE;
632649
sqe[0]->rw_flags = 0;
633650
cmd->tag = io->tag;
634651
cmd->q_id = q->q_id;
@@ -832,6 +849,7 @@ struct ublk_thread_info {
832849
unsigned idx;
833850
sem_t *ready;
834851
cpu_set_t *affinity;
852+
unsigned long long extra_flags;
835853
};
836854

837855
static void *ublk_io_handler_fn(void *data)
@@ -844,7 +862,7 @@ static void *ublk_io_handler_fn(void *data)
844862
t->dev = info->dev;
845863
t->idx = info->idx;
846864

847-
ret = ublk_thread_init(t);
865+
ret = ublk_thread_init(t, info->extra_flags);
848866
if (ret) {
849867
ublk_err("ublk dev %d thread %u init failed\n",
850868
dev_id, t->idx);
@@ -934,6 +952,8 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev)
934952

935953
if (ctx->auto_zc_fallback)
936954
extra_flags = UBLKS_Q_AUTO_BUF_REG_FALLBACK;
955+
if (ctx->no_ublk_fixed_fd)
956+
extra_flags |= UBLKS_Q_NO_UBLK_FIXED_FD;
937957

938958
for (i = 0; i < dinfo->nr_hw_queues; i++) {
939959
dev->q[i].dev = dev;
@@ -951,6 +971,7 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev)
951971
tinfo[i].dev = dev;
952972
tinfo[i].idx = i;
953973
tinfo[i].ready = &ready;
974+
tinfo[i].extra_flags = extra_flags;
954975

955976
/*
956977
* If threads are not tied 1:1 to queues, setting thread
@@ -1471,7 +1492,7 @@ static void __cmd_create_help(char *exe, bool recovery)
14711492
printf("%s %s -t [null|loop|stripe|fault_inject] [-q nr_queues] [-d depth] [-n dev_id]\n",
14721493
exe, recovery ? "recover" : "add");
14731494
printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1 ] [-g]\n");
1474-
printf("\t[-e 0|1 ] [-i 0|1]\n");
1495+
printf("\t[-e 0|1 ] [-i 0|1] [--no_ublk_fixed_fd]\n");
14751496
printf("\t[--nthreads threads] [--per_io_tasks]\n");
14761497
printf("\t[target options] [backfile1] [backfile2] ...\n");
14771498
printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n");
@@ -1534,6 +1555,7 @@ int main(int argc, char *argv[])
15341555
{ "size", 1, NULL, 's'},
15351556
{ "nthreads", 1, NULL, 0 },
15361557
{ "per_io_tasks", 0, NULL, 0 },
1558+
{ "no_ublk_fixed_fd", 0, NULL, 0 },
15371559
{ 0, 0, 0, 0 }
15381560
};
15391561
const struct ublk_tgt_ops *ops = NULL;
@@ -1613,6 +1635,8 @@ int main(int argc, char *argv[])
16131635
ctx.nthreads = strtol(optarg, NULL, 10);
16141636
if (!strcmp(longopts[option_idx].name, "per_io_tasks"))
16151637
ctx.per_io_tasks = 1;
1638+
if (!strcmp(longopts[option_idx].name, "no_ublk_fixed_fd"))
1639+
ctx.no_ublk_fixed_fd = 1;
16161640
break;
16171641
case '?':
16181642
/*

tools/testing/selftests/ublk/kublk.h

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct dev_ctx {
7777
unsigned int recovery:1;
7878
unsigned int auto_zc_fallback:1;
7979
unsigned int per_io_tasks:1;
80+
unsigned int no_ublk_fixed_fd:1;
8081

8182
int _evtfd;
8283
int _shmid;
@@ -166,7 +167,9 @@ struct ublk_queue {
166167

167168
/* borrow one bit of ublk uapi flags, which may never be used */
168169
#define UBLKS_Q_AUTO_BUF_REG_FALLBACK (1ULL << 63)
170+
#define UBLKS_Q_NO_UBLK_FIXED_FD (1ULL << 62)
169171
__u64 flags;
172+
int ublk_fd; /* cached ublk char device fd */
170173
struct ublk_io ios[UBLK_QUEUE_DEPTH];
171174
};
172175

@@ -273,34 +276,48 @@ static inline int ublk_io_alloc_sqes(struct ublk_thread *t,
273276
return nr_sqes;
274277
}
275278

276-
static inline void io_uring_prep_buf_register(struct io_uring_sqe *sqe,
277-
int dev_fd, int tag, int q_id, __u64 index)
279+
static inline int ublk_get_registered_fd(struct ublk_queue *q, int fd_index)
280+
{
281+
if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD) {
282+
if (fd_index == 0)
283+
/* Return the raw ublk FD for index 0 */
284+
return q->ublk_fd;
285+
/* Adjust index for backing files (index 1 becomes 0, etc.) */
286+
return fd_index - 1;
287+
}
288+
return fd_index;
289+
}
290+
291+
static inline void __io_uring_prep_buf_reg_unreg(struct io_uring_sqe *sqe,
292+
struct ublk_queue *q, int tag, int q_id, __u64 index)
278293
{
279294
struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd;
295+
int dev_fd = ublk_get_registered_fd(q, 0);
280296

281297
io_uring_prep_read(sqe, dev_fd, 0, 0, 0);
282298
sqe->opcode = IORING_OP_URING_CMD;
283-
sqe->flags |= IOSQE_FIXED_FILE;
284-
sqe->cmd_op = UBLK_U_IO_REGISTER_IO_BUF;
299+
if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD)
300+
sqe->flags &= ~IOSQE_FIXED_FILE;
301+
else
302+
sqe->flags |= IOSQE_FIXED_FILE;
285303

286304
cmd->tag = tag;
287305
cmd->addr = index;
288306
cmd->q_id = q_id;
289307
}
290308

291-
static inline void io_uring_prep_buf_unregister(struct io_uring_sqe *sqe,
292-
int dev_fd, int tag, int q_id, __u64 index)
309+
static inline void io_uring_prep_buf_register(struct io_uring_sqe *sqe,
310+
struct ublk_queue *q, int tag, int q_id, __u64 index)
293311
{
294-
struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd;
312+
__io_uring_prep_buf_reg_unreg(sqe, q, tag, q_id, index);
313+
sqe->cmd_op = UBLK_U_IO_REGISTER_IO_BUF;
314+
}
295315

296-
io_uring_prep_read(sqe, dev_fd, 0, 0, 0);
297-
sqe->opcode = IORING_OP_URING_CMD;
298-
sqe->flags |= IOSQE_FIXED_FILE;
316+
static inline void io_uring_prep_buf_unregister(struct io_uring_sqe *sqe,
317+
struct ublk_queue *q, int tag, int q_id, __u64 index)
318+
{
319+
__io_uring_prep_buf_reg_unreg(sqe, q, tag, q_id, index);
299320
sqe->cmd_op = UBLK_U_IO_UNREGISTER_IO_BUF;
300-
301-
cmd->tag = tag;
302-
cmd->addr = index;
303-
cmd->q_id = q_id;
304321
}
305322

306323
static inline void *ublk_get_sqe_cmd(const struct io_uring_sqe *sqe)

tools/testing/selftests/ublk/null.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ static int null_queue_zc_io(struct ublk_thread *t, struct ublk_queue *q,
6363

6464
ublk_io_alloc_sqes(t, sqe, 3);
6565

66-
io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
66+
io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
6767
sqe[0]->user_data = build_user_data(tag,
6868
ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1);
6969
sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK;
7070

7171
__setup_nop_io(tag, iod, sqe[1], q->q_id);
7272
sqe[1]->flags |= IOSQE_IO_HARDLINK;
7373

74-
io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
74+
io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index);
7575
sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1);
7676

7777
// buf register is marked as IOSQE_CQE_SKIP_SUCCESS

tools/testing/selftests/ublk/stripe.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ static int stripe_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q,
142142
ublk_io_alloc_sqes(t, sqe, s->nr + extra);
143143

144144
if (zc) {
145-
io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, io->buf_index);
145+
io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, io->buf_index);
146146
sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK;
147147
sqe[0]->user_data = build_user_data(tag,
148148
ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1);
@@ -168,7 +168,7 @@ static int stripe_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q,
168168
if (zc) {
169169
struct io_uring_sqe *unreg = sqe[s->nr + 1];
170170

171-
io_uring_prep_buf_unregister(unreg, 0, tag, q->q_id, io->buf_index);
171+
io_uring_prep_buf_unregister(unreg, q, tag, q->q_id, io->buf_index);
172172
unreg->user_data = build_user_data(
173173
tag, ublk_cmd_op_nr(unreg->cmd_op), 0, q->q_id, 1);
174174
}

tools/testing/selftests/ublk/test_stress_04.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ _create_backfile 0 256M
2828
_create_backfile 1 128M
2929
_create_backfile 2 128M
3030

31-
ublk_io_and_kill_daemon 8G -t null -q 4 -z &
32-
ublk_io_and_kill_daemon 256M -t loop -q 4 -z "${UBLK_BACKFILES[0]}" &
31+
ublk_io_and_kill_daemon 8G -t null -q 4 -z --no_ublk_fixed_fd &
32+
ublk_io_and_kill_daemon 256M -t loop -q 4 -z --no_ublk_fixed_fd "${UBLK_BACKFILES[0]}" &
3333
ublk_io_and_kill_daemon 256M -t stripe -q 4 -z "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
3434

3535
if _have_feature "AUTO_BUF_REG"; then
3636
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc &
3737
ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" &
38-
ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
38+
ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
3939
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
4040
fi
4141

0 commit comments

Comments
 (0)