diff mbox series

[v5,6/8] block: implement write zeroes io_uring cmd

Message ID 8e7975e44504d8371d716167face2bc8e248f7a4.1726072086.git.asml.silence@gmail.com (mailing list archive)
State New
Headers show
Series implement async block discards and other ops via io_uring | expand

Commit Message

Pavel Begunkov Sept. 11, 2024, 4:34 p.m. UTC
Add a second io_uring cmd for block layer implementing asynchronous
write zeroes. It reuses helpers we've added for async discards, and
inherits the code structure as well as all considerations in regards to
page cache races. It has to be supported by underlying hardware to be
used, otherwise the request will fail. A fallback version is implemented
separately in a later patch.

Suggested-by: Conrad Meyer <conradmeyer@meta.com>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 block/ioctl.c               | 66 +++++++++++++++++++++++++++++++++++++
 include/uapi/linux/blkdev.h |  1 +
 2 files changed, 67 insertions(+)

Comments

Christoph Hellwig Sept. 12, 2024, 9:32 a.m. UTC | #1
On Wed, Sep 11, 2024 at 05:34:42PM +0100, Pavel Begunkov wrote:
> Add a second io_uring cmd for block layer implementing asynchronous
> write zeroes. It reuses helpers we've added for async discards, and
> inherits the code structure as well as all considerations in regards to
> page cache races. It has to be supported by underlying hardware to be
> used, otherwise the request will fail. A fallback version is implemented
> separately in a later patch.

Except that as far as I can tell it doesn't implement a fallback, but
an entirely different command leading to applications breaking when
just using the command and the hardware doesn't support it.

Nacked-by: Christoph Hellwig <hch@lst.de>

to this incomplete API that will just create incompatbilities.
Pavel Begunkov Sept. 12, 2024, 4:25 p.m. UTC | #2
On 9/12/24 10:32, Christoph Hellwig wrote:
> On Wed, Sep 11, 2024 at 05:34:42PM +0100, Pavel Begunkov wrote:
>> Add a second io_uring cmd for block layer implementing asynchronous
>> write zeroes. It reuses helpers we've added for async discards, and
>> inherits the code structure as well as all considerations in regards to
>> page cache races. It has to be supported by underlying hardware to be
>> used, otherwise the request will fail. A fallback version is implemented
>> separately in a later patch.
> 
> Except that as far as I can tell it doesn't implement a fallback, but

I could've worded it better, but it doesn't say anything about
implementing fallback for this opcode.

> an entirely different command leading to applications breaking when
> just using the command and the hardware doesn't support it.
> 
> Nacked-by: Christoph Hellwig <hch@lst.de>
> 
> to this incomplete API that will just create incompatbilities.

That's fine, I'd rather take your nack than humouring the idea
of having a worse api than it could be.
Jens Axboe Sept. 12, 2024, 4:32 p.m. UTC | #3
On 9/12/24 10:25 AM, Pavel Begunkov wrote:
>> an entirely different command leading to applications breaking when
>> just using the command and the hardware doesn't support it.
>>
>> Nacked-by: Christoph Hellwig <hch@lst.de>
>>
>> to this incomplete API that will just create incompatbilities.
> 
> That's fine, I'd rather take your nack than humouring the idea
> of having a worse api than it could be.

How about we just drop 6-8 for now, and just focus on getting the actual
main discard operation in? That's (by far) the most important anyway,
and we can always add the write-zeroes bit later.
Pavel Begunkov Sept. 12, 2024, 4:53 p.m. UTC | #4
On 9/12/24 17:32, Jens Axboe wrote:
> On 9/12/24 10:25 AM, Pavel Begunkov wrote:
>>> an entirely different command leading to applications breaking when
>>> just using the command and the hardware doesn't support it.
>>>
>>> Nacked-by: Christoph Hellwig <hch@lst.de>
>>>
>>> to this incomplete API that will just create incompatbilities.
>>
>> That's fine, I'd rather take your nack than humouring the idea
>> of having a worse api than it could be.
> 
> How about we just drop 6-8 for now, and just focus on getting the actual
> main discard operation in? That's (by far) the most important anyway,
> and we can always add the write-zeroes bit later.

That's surely an option, and it's naturally up to you.

But to be clear, unless there are some new good arguments, I don't
buy those requested changes for 6-8 and refuse to go with it, that's
just creating a mess of flags cancelling each other down the line.
Jens Axboe Sept. 12, 2024, 4:59 p.m. UTC | #5
On 9/12/24 10:53 AM, Pavel Begunkov wrote:
> On 9/12/24 17:32, Jens Axboe wrote:
>> On 9/12/24 10:25 AM, Pavel Begunkov wrote:
>>>> an entirely different command leading to applications breaking when
>>>> just using the command and the hardware doesn't support it.
>>>>
>>>> Nacked-by: Christoph Hellwig <hch@lst.de>
>>>>
>>>> to this incomplete API that will just create incompatbilities.
>>>
>>> That's fine, I'd rather take your nack than humouring the idea
>>> of having a worse api than it could be.
>>
>> How about we just drop 6-8 for now, and just focus on getting the actual
>> main discard operation in? That's (by far) the most important anyway,
>> and we can always add the write-zeroes bit later.
> 
> That's surely an option, and it's naturally up to you.

Just trying to make forward progress - and since the actual discard is
the most interesting bit (imho), seems silly to gate it on the latter
bits.

> But to be clear, unless there are some new good arguments, I don't
> buy those requested changes for 6-8 and refuse to go with it, that's
> just creating a mess of flags cancelling each other down the line.

That's something to hash out, might be easier to do in person at LPC
next week.

For now I'll just drop 6-8.
Christoph Hellwig Sept. 13, 2024, 7:45 a.m. UTC | #6
On Thu, Sep 12, 2024 at 10:32:21AM -0600, Jens Axboe wrote:
> How about we just drop 6-8 for now, and just focus on getting the actual
> main discard operation in? That's (by far) the most important anyway,
> and we can always add the write-zeroes bit later.

Sounds fine to me.
diff mbox series

Patch

diff --git a/block/ioctl.c b/block/ioctl.c
index 007f6399de66..f8f6d6a71ff0 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -778,6 +778,69 @@  static void bio_cmd_bio_end_io(struct bio *bio)
 	bio_put(bio);
 }
 
+static int blkdev_cmd_write_zeroes(struct io_uring_cmd *cmd,
+				   struct block_device *bdev,
+				   uint64_t start, uint64_t len, bool nowait)
+{
+	struct blk_iou_cmd *bic = io_uring_cmd_to_pdu(cmd, struct blk_iou_cmd);
+	sector_t bs_mask = (bdev_logical_block_size(bdev) >> SECTOR_SHIFT) - 1;
+	sector_t limit = bdev_write_zeroes_sectors(bdev);
+	sector_t sector = start >> SECTOR_SHIFT;
+	sector_t nr_sects = len >> SECTOR_SHIFT;
+	struct bio *prev = NULL, *bio;
+	gfp_t gfp = nowait ? GFP_NOWAIT : GFP_KERNEL;
+	int err;
+
+	if (!(file_to_blk_mode(cmd->file) & BLK_OPEN_WRITE))
+		return -EBADF;
+	if (bdev_read_only(bdev))
+		return -EPERM;
+	err = blk_validate_byte_range(bdev, start, len);
+	if (err)
+		return err;
+
+	if (!limit)
+		return -EOPNOTSUPP;
+	/*
+	 * Don't allow multi-bio non-blocking submissions as subsequent bios
+	 * may fail but we won't get a direct indication of that. Normally,
+	 * the caller should retry from a blocking context.
+	 */
+	if (nowait && nr_sects > limit)
+		return -EAGAIN;
+
+	err = filemap_invalidate_pages(bdev->bd_mapping, start,
+					start + len - 1, nowait);
+	if (err)
+		return err;
+
+	limit = min(limit, (UINT_MAX >> SECTOR_SHIFT) & ~bs_mask);
+	while (nr_sects) {
+		sector_t bio_sects = min(nr_sects, limit);
+
+		bio = bio_alloc(bdev, 0, REQ_OP_WRITE_ZEROES|REQ_NOUNMAP, gfp);
+		if (!bio)
+			break;
+		if (nowait)
+			bio->bi_opf |= REQ_NOWAIT;
+		bio->bi_iter.bi_sector = sector;
+		bio->bi_iter.bi_size = bio_sects << SECTOR_SHIFT;
+		sector += bio_sects;
+		nr_sects -= bio_sects;
+
+		prev = bio_chain_and_submit(prev, bio);
+	}
+	if (unlikely(!prev))
+		return -EAGAIN;
+	if (unlikely(nr_sects))
+		bic->res = -EAGAIN;
+
+	prev->bi_private = cmd;
+	prev->bi_end_io = bio_cmd_bio_end_io;
+	submit_bio(prev);
+	return -EIOCBQUEUED;
+}
+
 static int blkdev_cmd_discard(struct io_uring_cmd *cmd,
 			      struct block_device *bdev,
 			      uint64_t start, uint64_t len, bool nowait)
@@ -856,6 +919,9 @@  int blkdev_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 	switch (cmd_op) {
 	case BLOCK_URING_CMD_DISCARD:
 		return blkdev_cmd_discard(cmd, bdev, start, len, bic->nowait);
+	case BLOCK_URING_CMD_WRITE_ZEROES:
+		return blkdev_cmd_write_zeroes(cmd, bdev, start, len,
+					       bic->nowait);
 	}
 	return -EINVAL;
 }
diff --git a/include/uapi/linux/blkdev.h b/include/uapi/linux/blkdev.h
index 66373cd1a83a..b4664139a82a 100644
--- a/include/uapi/linux/blkdev.h
+++ b/include/uapi/linux/blkdev.h
@@ -10,5 +10,6 @@ 
  * It's a different number space from ioctl(), reuse the block's code 0x12.
  */
 #define BLOCK_URING_CMD_DISCARD			_IO(0x12, 0)
+#define BLOCK_URING_CMD_WRITE_ZEROES		_IO(0x12, 1)
 
 #endif