* [PATCH liburing 0/3] support for discard block commands
@ 2024-10-13 20:45 Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 1/3] Add io_uring_prep_cmd_discard Pavel Begunkov
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Pavel Begunkov @ 2024-10-13 20:45 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe, asml.silence
Add helpers for the block layer discard commands, as well as
some tests and man pages.
Pavel Begunkov (3):
Add io_uring_prep_cmd_discard
test: add discard cmd tests
man/io_uring_prep_cmd_discard.3: add discard man pages
configure | 32 +++
man/io_uring_prep_cmd_discard.3 | 60 +++++
src/include/liburing.h | 10 +
test/Makefile | 1 +
test/cmd-discard.c | 402 ++++++++++++++++++++++++++++++++
5 files changed, 505 insertions(+)
create mode 100644 man/io_uring_prep_cmd_discard.3
create mode 100644 test/cmd-discard.c
--
2.46.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH liburing 1/3] Add io_uring_prep_cmd_discard
2024-10-13 20:45 [PATCH liburing 0/3] support for discard block commands Pavel Begunkov
@ 2024-10-13 20:45 ` Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 2/3] test: add discard cmd tests Pavel Begunkov
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2024-10-13 20:45 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe, asml.silence
Add a helper for io_uring block discard commands. Since the discard
opcode is in newly added linux/blkdev.h we need to do some configure
magic defining it ourselves if the header is missing from the system.
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
configure | 32 ++++++++++++++++++++++++++++++++
src/include/liburing.h | 10 ++++++++++
2 files changed, 42 insertions(+)
diff --git a/configure b/configure
index e2221d3..6c9cea0 100755
--- a/configure
+++ b/configure
@@ -417,6 +417,21 @@ if compile_prog "" "" "futexv"; then
fi
print_config "futex waitv support" "$futexv"
+##########################################
+# Check block discard cmd support
+discard_cmd="no"
+cat > $TMPC << EOF
+#include <linux/blkdev.h>
+int main(void)
+{
+ return BLOCK_URING_CMD_DISCARD;
+}
+EOF
+if compile_prog "" "" "discard command"; then
+ discard_cmd="yes"
+fi
+print_config "io_uring discard command support" "$discard_cmd"
+
##########################################
# Check idtype_t support
has_idtype_t="no"
@@ -651,6 +666,23 @@ typedef enum
} idtype_t;
EOF
fi
+
+if test "$discard_cmd" != "yes"; then
+cat >> $compat_h << EOF
+
+#include <linux/ioctl.h>
+
+#ifndef BLOCK_URING_CMD_DISCARD
+#define BLOCK_URING_CMD_DISCARD _IO(0x12, 0)
+#endif
+
+EOF
+else cat >> $discard_cmd << EOF
+#include <linux/blkdev.h>
+
+EOF
+fi
+
cat >> $compat_h << EOF
#endif
EOF
diff --git a/src/include/liburing.h b/src/include/liburing.h
index c5a2fda..f5903d7 100644
--- a/src/include/liburing.h
+++ b/src/include/liburing.h
@@ -1292,6 +1292,16 @@ IOURINGINLINE void io_uring_prep_ftruncate(struct io_uring_sqe *sqe,
}
#endif
+IOURINGINLINE void io_uring_prep_cmd_discard(struct io_uring_sqe *sqe,
+ int fd,
+ uint64_t offset, uint64_t nbytes)
+{
+ io_uring_prep_rw(IORING_OP_URING_CMD, sqe, fd, 0, 0, 0);
+ sqe->cmd_op = BLOCK_URING_CMD_DISCARD;
+ sqe->addr = offset;
+ sqe->addr3 = nbytes;
+}
+
/*
* Returns number of unconsumed (if SQPOLL) or unsubmitted entries exist in
* the SQ ring
--
2.46.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH liburing 2/3] test: add discard cmd tests
2024-10-13 20:45 [PATCH liburing 0/3] support for discard block commands Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 1/3] Add io_uring_prep_cmd_discard Pavel Begunkov
@ 2024-10-13 20:45 ` Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 3/3] man/io_uring_prep_cmd_discard.3: add discard man pages Pavel Begunkov
2024-10-14 13:27 ` [PATCH liburing 0/3] support for discard block commands Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2024-10-13 20:45 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe, asml.silence
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
test/Makefile | 1 +
test/cmd-discard.c | 402 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 403 insertions(+)
create mode 100644 test/cmd-discard.c
diff --git a/test/Makefile b/test/Makefile
index de5f98d..b22c3f1 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -65,6 +65,7 @@ test_srcs := \
connect.c \
connect-rep.c \
coredump.c \
+ cmd-discard.c \
cq-full.c \
cq-overflow.c \
cq-peek-batch.c \
diff --git a/test/cmd-discard.c b/test/cmd-discard.c
new file mode 100644
index 0000000..4d7f91e
--- /dev/null
+++ b/test/cmd-discard.c
@@ -0,0 +1,402 @@
+/* SPDX-License-Identifier: MIT */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define MAX_TEST_LBAS 1024
+
+static const char *filename;
+static int opcodes[] = {
+ BLOCK_URING_CMD_DISCARD,
+};
+
+static int lba_size;
+static uint64_t bdev_size;
+static uint64_t bdev_size_lbas;
+static char *buffer;
+
+#define TEST_BLOCK_URING_CMD_MAX 3
+
+static void prep_blk_cmd(struct io_uring_sqe *sqe, int fd,
+ uint64_t from, uint64_t len,
+ int cmd_op)
+{
+ assert(cmd_op == BLOCK_URING_CMD_DISCARD);
+
+ io_uring_prep_cmd_discard(sqe, fd, from, len);
+}
+
+static int queue_cmd_range(struct io_uring *ring, int bdev_fd,
+ uint64_t from, uint64_t len, int cmd_op)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int err;
+
+ sqe = io_uring_get_sqe(ring);
+ assert(sqe != NULL);
+ prep_blk_cmd(sqe, bdev_fd, from, len, cmd_op);
+
+ err = io_uring_submit_and_wait(ring, 1);
+ if (err != 1) {
+ fprintf(stderr, "io_uring_submit_and_wait failed %d\n", err);
+ exit(1);
+ }
+
+ err = io_uring_wait_cqe(ring, &cqe);
+ if (err) {
+ fprintf(stderr, "io_uring_wait_cqe failed %d (op %i)\n",
+ err, cmd_op);
+ exit(1);
+ }
+
+ err = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ return err;
+}
+
+static int queue_cmd_lba(struct io_uring *ring, int bdev_fd,
+ uint64_t from, uint64_t nr_lba, int cmd_op)
+{
+ return queue_cmd_range(ring, bdev_fd, from * lba_size,
+ nr_lba * lba_size, cmd_op);
+}
+
+static int queue_discard_lba(struct io_uring *ring, int bdev_fd,
+ uint64_t from, uint64_t nr_lba)
+{
+ return queue_cmd_lba(ring, bdev_fd, from, nr_lba,
+ BLOCK_URING_CMD_DISCARD);
+}
+
+static int test_parallel(struct io_uring *ring, int fd, int cmd_op)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int inflight = 0;
+ int max_inflight = 16;
+ int left = 1000;
+ int ret;
+
+ while (left || inflight) {
+ int queued = 0;
+ unsigned head, nr_cqes = 0;
+ int lba_len = 8;
+
+ while (inflight < max_inflight && left) {
+ int off = rand() % (MAX_TEST_LBAS - lba_len);
+ sqe = io_uring_get_sqe(ring);
+ assert(sqe != NULL);
+
+ prep_blk_cmd(sqe, fd, off * lba_size,
+ lba_len * lba_size, cmd_op);
+ if (rand() & 1)
+ sqe->flags |= IOSQE_ASYNC;
+
+ queued++;
+ left--;
+ inflight++;
+ }
+ if (queued) {
+ ret = io_uring_submit(ring);
+ if (ret != queued) {
+ fprintf(stderr, "io_uring_submit failed %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ }
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "io_uring_wait_cqe failed %d\n", ret);
+ exit(1);
+ }
+
+ io_uring_for_each_cqe(ring, head, cqe) {
+ nr_cqes++;
+ inflight--;
+ if (cqe->res != 0) {
+ fprintf(stderr, "cmd %i failed %i\n", cmd_op,
+ cqe->res);
+ return T_EXIT_FAIL;
+ }
+ }
+ io_uring_cq_advance(ring, nr_cqes);
+ }
+
+ return 0;
+}
+
+static int cmd_issue_verify(struct io_uring *ring, int fd, int lba, int len,
+ int cmd_op)
+{
+ int verify = (cmd_op != BLOCK_URING_CMD_DISCARD);
+ int ret, i;
+ ssize_t res;
+
+ if (verify) {
+ for (i = 0; i < len; i++) {
+ size_t off = (i + lba) * lba_size;
+
+ res = pwrite(fd, buffer, lba_size, off);
+ if (res == -1) {
+ fprintf(stderr, "pwrite failed\n");
+ return T_EXIT_FAIL;
+ }
+ }
+ }
+
+ ret = queue_cmd_lba(ring, fd, lba, len, cmd_op);
+ if (ret) {
+ if (ret == -EINVAL || ret == -EOPNOTSUPP)
+ return T_EXIT_SKIP;
+
+ fprintf(stderr, "cmd_issue_verify %i fail lba %i len %i ret %i\n",
+ cmd_op, lba, len, ret);
+ return T_EXIT_FAIL;
+ }
+
+ if (verify) {
+ for (i = 0; i < len; i++) {
+ size_t off = (i + lba) * lba_size;
+
+ res = pread(fd, buffer, lba_size, off);
+ if (res == -1) {
+ fprintf(stderr, "pread failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (!memchr(buffer, 0, lba_size)) {
+ fprintf(stderr, "mem cmp failed, lba %i\n", lba + i);
+ return T_EXIT_FAIL;
+ }
+ }
+ }
+ return 0;
+}
+
+static int basic_cmd_test(struct io_uring *ring, int cmd_op)
+{
+ int ret, fd;
+
+ fd = open(filename, O_DIRECT | O_RDWR | O_EXCL);
+ if (fd < 0) {
+ fprintf(stderr, "open failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ ret = cmd_issue_verify(ring, fd, 0, 1, cmd_op);
+ if (ret == T_EXIT_SKIP) {
+ printf("cmd %i not supported, skip\n", cmd_op);
+ close(fd);
+ return T_EXIT_SKIP;
+ } else if (ret) {
+ fprintf(stderr, "cmd %i fail 0 1\n", cmd_op);
+ return T_EXIT_FAIL;
+ }
+
+ ret = cmd_issue_verify(ring, fd, 7, 15, cmd_op);
+ if (ret) {
+ fprintf(stderr, "cmd %i fail 7 15 %i\n", cmd_op, ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = cmd_issue_verify(ring, fd, 1, MAX_TEST_LBAS - 1, cmd_op);
+ if (ret) {
+ fprintf(stderr, "large cmd %i failed %i\n", cmd_op, ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_parallel(ring, fd, cmd_op);
+ if (ret) {
+ fprintf(stderr, "test_parallel() %i failed %i\n", cmd_op, ret);
+ return T_EXIT_FAIL;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int test_fail_edge_cases(struct io_uring *ring, int cmd_op)
+{
+ int ret, fd;
+
+ fd = open(filename, O_DIRECT | O_RDWR | O_EXCL);
+ if (fd < 0) {
+ fprintf(stderr, "open failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ ret = queue_cmd_lba(ring, fd, bdev_size_lbas, 1, cmd_op);
+ if (ret >= 0) {
+ fprintf(stderr, "cmd %i beyond capacity %i\n",
+ cmd_op, ret);
+ return 1;
+ }
+
+ ret = queue_cmd_lba(ring, fd, bdev_size_lbas - 1, 2, cmd_op);
+ if (ret >= 0) {
+ fprintf(stderr, "cmd %i beyond capacity with overlap %i\n",
+ cmd_op, ret);
+ return 1;
+ }
+
+ ret = queue_cmd_range(ring, fd, (uint64_t)-lba_size, lba_size + 2,
+ cmd_op);
+ if (ret >= 0) {
+ fprintf(stderr, "cmd %i range overflow %i\n",
+ cmd_op, ret);
+ return 1;
+ }
+
+ ret = queue_cmd_range(ring, fd, lba_size / 2, lba_size, cmd_op);
+ if (ret >= 0) {
+ fprintf(stderr, "cmd %i unaligned offset %i\n",
+ cmd_op, ret);
+ return 1;
+ }
+
+ ret = queue_cmd_range(ring, fd, 0, lba_size / 2, cmd_op);
+ if (ret >= 0) {
+ fprintf(stderr, "cmd %i unaligned size %i\n",
+ cmd_op, ret);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int test_rdonly(struct io_uring *ring, int cmd_op)
+{
+ int ret, fd;
+ int ro;
+
+ fd = open(filename, O_DIRECT | O_RDONLY | O_EXCL);
+ if (fd < 0) {
+ fprintf(stderr, "open failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ ret = queue_discard_lba(ring, fd, 0, 1);
+ if (ret >= 0) {
+ fprintf(stderr, "discarded with O_RDONLY %i\n", ret);
+ return 1;
+ }
+ close(fd);
+
+ fd = open(filename, O_DIRECT | O_RDWR | O_EXCL);
+ if (fd < 0) {
+ fprintf(stderr, "open failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ ro = 1;
+ ret = ioctl(fd, BLKROSET, &ro);
+ if (ret) {
+ fprintf(stderr, "BLKROSET 1 failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ ret = queue_discard_lba(ring, fd, 0, 1);
+ if (ret >= 0) {
+ fprintf(stderr, "discarded with O_RDONLY %i\n", ret);
+ return 1;
+ }
+
+ ro = 0;
+ ret = ioctl(fd, BLKROSET, &ro);
+ if (ret) {
+ fprintf(stderr, "BLKROSET 0 failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+ close(fd);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ int fd, ret, i;
+ int cmd_op;
+
+ if (argc != 2)
+ return T_SETUP_SKIP;
+ filename = argv[1];
+
+ fd = open(filename, O_DIRECT | O_RDONLY | O_EXCL);
+ if (fd < 0) {
+ fprintf(stderr, "open failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ ret = ioctl(fd, BLKGETSIZE64, &bdev_size);
+ if (ret < 0) {
+ fprintf(stderr, "BLKGETSIZE64 failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+ ret = ioctl(fd, BLKSSZGET, &lba_size);
+ if (ret < 0) {
+ fprintf(stderr, "BLKSSZGET failed %i\n", errno);
+ return T_EXIT_FAIL;
+ }
+ assert(bdev_size % lba_size == 0);
+ bdev_size_lbas = bdev_size / lba_size;
+ close(fd);
+
+ buffer = aligned_alloc(lba_size, lba_size);
+ if (!buffer) {
+ fprintf(stderr, "aligned_alloc failed\n");
+ return T_EXIT_FAIL;
+ }
+ for (i = 0; i < lba_size; i++)
+ buffer[i] = i ^ 0xA7;
+
+ if (bdev_size_lbas < MAX_TEST_LBAS) {
+ fprintf(stderr, "the device is too small, skip\n");
+ return T_EXIT_SKIP;
+ }
+
+ ret = io_uring_queue_init(16, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "queue init failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+
+ for (cmd_op = 0; cmd_op < TEST_BLOCK_URING_CMD_MAX; cmd_op++) {
+ ret = basic_cmd_test(&ring, opcodes[cmd_op]);
+ if (ret) {
+ if (ret == T_EXIT_SKIP)
+ continue;
+
+ fprintf(stderr, "basic_cmd_test() failed, cmd %i\n",
+ cmd_op);
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_rdonly(&ring, opcodes[cmd_op]);
+ if (ret) {
+ fprintf(stderr, "test_rdonly() failed, cmd %i\n",
+ cmd_op);
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_fail_edge_cases(&ring, opcodes[cmd_op]);
+ if (ret) {
+ fprintf(stderr, "test_fail_edge_cases() failed, cmd %i\n",
+ cmd_op);
+ return T_EXIT_FAIL;
+ }
+ }
+
+ io_uring_queue_exit(&ring);
+ free(buffer);
+ return 0;
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH liburing 3/3] man/io_uring_prep_cmd_discard.3: add discard man pages
2024-10-13 20:45 [PATCH liburing 0/3] support for discard block commands Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 1/3] Add io_uring_prep_cmd_discard Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 2/3] test: add discard cmd tests Pavel Begunkov
@ 2024-10-13 20:45 ` Pavel Begunkov
2024-10-14 13:27 ` [PATCH liburing 0/3] support for discard block commands Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2024-10-13 20:45 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe, asml.silence
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
man/io_uring_prep_cmd_discard.3 | 60 +++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 man/io_uring_prep_cmd_discard.3
diff --git a/man/io_uring_prep_cmd_discard.3 b/man/io_uring_prep_cmd_discard.3
new file mode 100644
index 0000000..75e25bb
--- /dev/null
+++ b/man/io_uring_prep_cmd_discard.3
@@ -0,0 +1,60 @@
+.\" Copyright (C) 2024 Pavel Begunkov <asml.silence@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+.TH io_uring_prep_cmd_discard 3 "Oct 13, 2024" "liburing-2.8" "liburing Manual"
+.SH NAME
+io_uring_prep_cmd_discard \- prepare a discard command
+.SH SYNOPSIS
+.nf
+.B #include <liburing.h>
+.PP
+.BI "void io_uring_prep_cmd_discard(struct io_uring_sqe *" sqe ","
+.BI " int " fd ","
+.BI " uint64_t " offset ","
+.BI " uint64_t " nbytes ");"
+.fi
+.SH DESCRIPTION
+The
+.BR io_uring_prep_cmd_discard (3)
+function prepares a discard command request. The submission queue entry
+.I sqe
+is setup to use the file descriptor
+.IR fd
+to start discarding
+.I nbytes
+at the specified
+.IR offset .
+
+The command is an asynchronous equivalent of
+.B BLOCK_URING_CMD_DISCARD
+ioctl with a few differences. It allows multiple parallel discards, and it does
+not exclude concurrent writes and reads. As a result, it may lead to races for
+the data on the disk, and it's the user's responsibility to account for that.
+Furthermore, we only do best effort to invalidate page caches, the user has
+to make sure there are no other inflight requests are modifying or reading
+the range(s), otherwise it might result in stale page cache and data
+inconsistencies.
+
+Available since 6.12.
+
+.SH RETURN VALUE
+None
+.SH ERRORS
+The CQE
+.I res
+field will contain the result of the operation. See the related man page for
+details on possible values. Note that where synchronous system calls will return
+.B -1
+on failure and set
+.I errno
+to the actual error value, io_uring never uses
+.IR errno .
+Instead it returns the negated
+.I errno
+directly in the CQE
+.I res
+field.
+.SH SEE ALSO
+.BR io_uring_get_sqe (3),
+.BR io_uring_submit (3),
--
2.46.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH liburing 0/3] support for discard block commands
2024-10-13 20:45 [PATCH liburing 0/3] support for discard block commands Pavel Begunkov
` (2 preceding siblings ...)
2024-10-13 20:45 ` [PATCH liburing 3/3] man/io_uring_prep_cmd_discard.3: add discard man pages Pavel Begunkov
@ 2024-10-14 13:27 ` Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2024-10-14 13:27 UTC (permalink / raw)
To: io-uring, Pavel Begunkov
On Sun, 13 Oct 2024 21:45:43 +0100, Pavel Begunkov wrote:
> Add helpers for the block layer discard commands, as well as
> some tests and man pages.
>
> Pavel Begunkov (3):
> Add io_uring_prep_cmd_discard
> test: add discard cmd tests
> man/io_uring_prep_cmd_discard.3: add discard man pages
>
> [...]
Applied, thanks!
[1/3] Add io_uring_prep_cmd_discard
commit: 906a4567312346a688ccb05ae94459cb00b889a6
[2/3] test: add discard cmd tests
commit: 244be25e45c32981008cf50c9923d0ea1bd4e2e5
[3/3] man/io_uring_prep_cmd_discard.3: add discard man pages
commit: bafd87251db3fa942c310eb8afd137b6c3cd0369
Best regards,
--
Jens Axboe
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-10-14 13:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-13 20:45 [PATCH liburing 0/3] support for discard block commands Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 1/3] Add io_uring_prep_cmd_discard Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 2/3] test: add discard cmd tests Pavel Begunkov
2024-10-13 20:45 ` [PATCH liburing 3/3] man/io_uring_prep_cmd_discard.3: add discard man pages Pavel Begunkov
2024-10-14 13:27 ` [PATCH liburing 0/3] support for discard block commands Jens Axboe
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.