From patchwork Wed Sep 4 14:18:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Begunkov X-Patchwork-Id: 13790935 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id EAEB2CD37B4 for ; Wed, 4 Sep 2024 14:17:59 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2080E8D025B; Wed, 4 Sep 2024 10:17:54 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 1B5EE8D0253; Wed, 4 Sep 2024 10:17:54 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 007138D025B; Wed, 4 Sep 2024 10:17:53 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id C85698D0253 for ; Wed, 4 Sep 2024 10:17:53 -0400 (EDT) Received: from smtpin09.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 932C51A1580 for ; Wed, 4 Sep 2024 14:17:53 +0000 (UTC) X-FDA: 82527259626.09.848399D Received: from mail-ej1-f47.google.com (mail-ej1-f47.google.com [209.85.218.47]) by imf07.hostedemail.com (Postfix) with ESMTP id 89B7640029 for ; Wed, 4 Sep 2024 14:17:51 +0000 (UTC) Authentication-Results: imf07.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=WiXUzoJ+; spf=pass (imf07.hostedemail.com: domain of asml.silence@gmail.com designates 209.85.218.47 as permitted sender) smtp.mailfrom=asml.silence@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1725459423; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=v7dFMMDbVFAIV5pvquHCkne/t7NzjwwosACmczIEiUs=; b=FaoWkaeo5BX0aYiCgNDy4JrynRoDS0IL9fWuDXAbrfN7e4UQipv+i7H38XAEVbOughxwrg L5wQyJhEXe+RosaIH6OSzyuuEciykfY1Y632XbPPk4cur0IUJaYvwG5si2PjV50DGsxmb5 7wzVWUroLu5mejcSefGghXcLg78k3Ig= ARC-Authentication-Results: i=1; imf07.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=WiXUzoJ+; spf=pass (imf07.hostedemail.com: domain of asml.silence@gmail.com designates 209.85.218.47 as permitted sender) smtp.mailfrom=asml.silence@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1725459423; a=rsa-sha256; cv=none; b=8XNcGGE5t9uWNp214+t5g4A7tK/y3Vv++7iGwU65OtH1S02FCkupFMRBDTHG0MrnK2p4NJ 4XcokV/o2fdahaQaoxt0FInlJlJepIkthTH6yCr1Q4WVdqbH1oLljdCOsXy8DKMgB0Ghaz kanHMo5ULvNrSw4GZp0LPR4an5uhO3U= Received: by mail-ej1-f47.google.com with SMTP id a640c23a62f3a-a8a1acb51a7so305592966b.2 for ; Wed, 04 Sep 2024 07:17:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1725459470; x=1726064270; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=v7dFMMDbVFAIV5pvquHCkne/t7NzjwwosACmczIEiUs=; b=WiXUzoJ+uVEgqGuNSPYMjTdGXGOZ6oTlGyV0xj17FwinUd5MzCeDsejm+ixQLuvQdU lGGczB1Ut1FlR9s50GjKChuMiSi8fnxgC/AZgG9oRmcpLFJHzO7hCBZFc52eLlp9g1hg lQCXEt2/aqno8rf1ed05ZckOnPWo39bz0fZRY1EZ/Q3Wew3Xzpo90Q0QUXczTMwZacGN IhoojpC4rTgOjFCs6vqsqZrzIrmh/RaKehkYZYaY1Q4zRDpcZULmdtnb5kTHlk56OPKb N3SfyjlJbfUTN7BCoWYzTx4S93W4SXjH5zXaA6o3Vt29mvN1HLrbtvvMfX9sPysdL0/b i5hg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1725459470; x=1726064270; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=v7dFMMDbVFAIV5pvquHCkne/t7NzjwwosACmczIEiUs=; b=WYZaZROaz+Pb+FZrgaOgxFTmybCvCxanV2fl5bdcLnSBnY0cIiRWMPdP5JNI5qXj5O 3U45EW8oVJuMJcPGIpabR8U8/yXHn57uC8ZgJPSXq/0+hJUzqzjLiR48Sx+dfEuEbsQA 1PBriSdGuxFendg3otDy9ztcLmq07HHQfF9B2PLhMq6Hj5Zj7NeD2KihvPwUs7s+uZDO Do0RbQLWdkscZ/EiWkeK7cPSEIYZ4RnX+tKVrsrRllwYtP0gNqoTtCdR9yCAiWSEor87 HFKSS7mQf2kNBkmfvmq1+5T1mvJbD4se26Wy1CGOheuLyCU9FGNkg56m47gwGcD/KwIy zyZQ== X-Forwarded-Encrypted: i=1; AJvYcCVS9EZkf/OITCgpoWe1u5/99eDb1JB1j/OkY+sZs1CPdti9qzek9mpQXB57Wdr7YeT43AoHco7wLQ==@kvack.org X-Gm-Message-State: AOJu0YwQHgd+TyAVpS3iP5RJuf/lAmO5vWUnMMg9HvVjMszpNsOj5TX6 JWXMp4Ztxe1PPvg8qtg6UWXHtQEdLi9Kq5p8Z9K1uH0Epku0Lgql X-Google-Smtp-Source: AGHT+IE26wVQR2LgzuFQ4epQHPbTKn3Zvnc693bAIlnah2akuYCekc7BKlc1sYCNhwYDpPPSQe9AfA== X-Received: by 2002:a17:907:7e9b:b0:a86:6cb1:4d49 with SMTP id a640c23a62f3a-a8a1d29b736mr490505366b.13.1725459469967; Wed, 04 Sep 2024 07:17:49 -0700 (PDT) Received: from 127.0.0.1localhost ([163.114.131.193]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a8989196c88sm811160766b.102.2024.09.04.07.17.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Sep 2024 07:17:49 -0700 (PDT) From: Pavel Begunkov To: io-uring@vger.kernel.org Cc: Jens Axboe , asml.silence@gmail.com, Conrad Meyer , linux-block@vger.kernel.org, linux-mm@kvack.org, Christoph Hellwig Subject: [PATCH v3 5/8] block: implement async discard as io_uring cmd Date: Wed, 4 Sep 2024 15:18:04 +0100 Message-ID: <7fc0a61ae29190a42e958eddfefd6d44cdf372ad.1725459175.git.asml.silence@gmail.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam03 X-Rspam-User: X-Rspamd-Queue-Id: 89B7640029 X-Stat-Signature: qw7gner1hkrckch3rmdg933ibyorrkf5 X-HE-Tag: 1725459471-645567 X-HE-Meta: U2FsdGVkX18hp+ESCTUuZGsn91IavyvM9gtqoTS2Y4WIajhDOT9EGVTMUFMFRnr8hVyhlRMf2Er1PrjWXaLZSR2X8xKlxoCxK2rHmgrk7LjFd8DOFB0RZT1jVvshh8+571CZyS/5NMGqFIhCT80EOPS5vUtgVkG4lBHgt3WDpaXegm2V/c/sC0EmxI0V6f/cL7g4fse2OZAJV8/+r8r9H9jU8bzlOHU9LXXCxSa+BngD/hteCwqApWnLBv0KUPt0uHzXbL3+BgG0gYFAFH5tnnG0Ma89IVof/UvBPADQdDnBYSEzBbm/Qlfwp/eM8HIV5Oyu9ivrhqq5zXyUkU1cDmkP4+H9q5yxiygOXgEFW9FWRQJMNTNEWyPRRy57BDS/dGhg0dDvOYC9RKzq+J0wN4wEFcBUaoYQtka2qY0XeEXu1F6JDM/MP90pdYZqgq1lm/n4im8VJSaBo3htXpQ+eZScORZGf5+wccHodA5caRJGo6VDZrdherME6aRIAGfMGE5hP2lU+nrbZbEL5r+vCS1Nb3YTv2n5MIcTfLhIZq6QdQ0HbRVCJr4cXkiYgvURCgh9bdueifaQ0dnXowBNRKaEkzubNxtQTqWbKqzPCKGKfgZWxbOTDCJbadlkb6mul7WGVkKL5XO/HR1rNOZnSWFMvHvkMGHvO85Vz6DaL88Lc9LVdkV6WZHAcIK3CWTg6tE1OgGCROx/gOwCECM1WWYGGEoUHw+xNRXZ8NyY2PrWoLNoUDl4KdhPvO7Jyz8KZMnESeLVKTBAyjdZ8t1aLzDfTEMay30bRFwPy8neSl8x2IPHSOKmaahtQtpE6fSHr05zOXuEYfixBGmoj+kdkmzypwL5EYvi4ZgPpdK+UEjr9+9nizBSe9VttHKGWOb3DrqViSOTCpOdRkcHwx0gvRx6MhLM6rVkGaY+R1juKlq5PlGdTKDIRNMTg2npu/a/gyb81I843ty/VqtCM83 4BBpCJTJ im+6e8oS1cFNZUij01mB/q5H9V9ZWJXs8DZdmWn6bNpHvg865sck+jg/LxQsJm00tSN9SKyGAkHRB72TxPVQIIHihfO31zI/81dgRrmj9fGC/2BogkBpdkWeSvvefZ9b+NpHcG/lmzeRVHgac33uhir7VQhBYCZtFt9Zz2V9n3V9vbyyik9Yv8A78yyIquMM54RtNaMj1pKeaVWATSZhjA1L3KjVMLj5aUdTpxfqE5UsxO8cP5aMm+Y+VY5qCFzRQuFYvpuFwBNZhLENqU66BEASsPmYxa2cnpyDStqEIQZ4gAwoEncDqyabXgdW3r5YDMcxXWu92etANLxkjbzDVF4DbxpsjyjjzN5UTJ/pFZt+Rt9hw7hDZYK8unzQS4RCzv2s5w5FsWD8vW360cUaqRM8yAT60fBZXfP6oTTNGWmFjA6F6HFEvGCcGRxA7Q+2J9yTaiPf+y05Gd7nT/Ggh1X5sGES9pPeOThR6K1HPXToOBOGSzwt5KQn0Y8PUOJbdgWcXN5AARDRq3BT40Gmkb49EPECLnuJPqBCvIKAW2SNC4wPJqtvN3IHgo2icmaHZKg4OXHmSeolISY0= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: io_uring allows to implement custom file specific operations via fops->uring_cmd callback. Use it to wire up asynchronous discard commands. Normally, first it tries to do a non-blocking issue, and if fails we'd retry from a blocking context by returning -EAGAIN to core io_uring. Note, unlike ioctl(BLKDISCARD) with stronger guarantees against races, we only do a best effort attempt to invalidate page cache, and it can race with any writes and reads and leave page cache stale. It's the same kind of races we allow to direct writes. Suggested-by: Conrad Meyer Signed-off-by: Pavel Begunkov --- block/blk-lib.c | 3 +- block/blk.h | 1 + block/fops.c | 2 + block/ioctl.c | 102 ++++++++++++++++++++++++++++++++++++++++ include/linux/bio.h | 2 + include/uapi/linux/fs.h | 2 + 6 files changed, 111 insertions(+), 1 deletion(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index 83eb7761c2bf..c94c67a75f7e 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -10,7 +10,8 @@ #include "blk.h" -static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector) +/* The maximum size of a discard that can be issued from a given sector. */ +sector_t bio_discard_limit(struct block_device *bdev, sector_t sector) { unsigned int discard_granularity = bdev_discard_granularity(bdev); sector_t granularity_aligned_sector; diff --git a/block/blk.h b/block/blk.h index 32f4e9f630a3..1a1a18d118f7 100644 --- a/block/blk.h +++ b/block/blk.h @@ -605,6 +605,7 @@ blk_mode_t file_to_blk_mode(struct file *file); int truncate_bdev_range(struct block_device *bdev, blk_mode_t mode, loff_t lstart, loff_t lend); long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg); +int blkdev_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags); long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg); extern const struct address_space_operations def_blk_aops; diff --git a/block/fops.c b/block/fops.c index 9825c1713a49..8154b10b5abf 100644 --- a/block/fops.c +++ b/block/fops.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "blk.h" static inline struct inode *bdev_file_inode(struct file *file) @@ -873,6 +874,7 @@ const struct file_operations def_blk_fops = { .splice_read = filemap_splice_read, .splice_write = iter_file_splice_write, .fallocate = blkdev_fallocate, + .uring_cmd = blkdev_uring_cmd, .fop_flags = FOP_BUFFER_RASYNC, }; diff --git a/block/ioctl.c b/block/ioctl.c index a820f692dd1c..19fba8332eee 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "blk.h" static int blkpg_do_ioctl(struct block_device *bdev, @@ -742,3 +744,103 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return ret; } #endif + +struct blk_iou_cmd { + int res; + bool nowait; +}; + +static void blk_cmd_complete(struct io_uring_cmd *cmd, unsigned int issue_flags) +{ + struct blk_iou_cmd *bic = io_uring_cmd_to_pdu(cmd, struct blk_iou_cmd); + + if (bic->res == -EAGAIN && bic->nowait) + io_uring_cmd_issue_blocking(cmd); + else + io_uring_cmd_done(cmd, bic->res, 0, issue_flags); +} + +static void bio_cmd_bio_end_io(struct bio *bio) +{ + struct io_uring_cmd *cmd = bio->bi_private; + struct blk_iou_cmd *bic = io_uring_cmd_to_pdu(cmd, struct blk_iou_cmd); + + if (unlikely(bio->bi_status) && !bic->res) + bic->res = blk_status_to_errno(bio->bi_status); + + io_uring_cmd_do_in_task_lazy(cmd, blk_cmd_complete); + bio_put(bio); +} + +static int blkdev_cmd_discard(struct io_uring_cmd *cmd, + struct block_device *bdev, + uint64_t start, uint64_t len, bool nowait) +{ + gfp_t gfp = nowait ? GFP_NOWAIT : GFP_KERNEL; + sector_t sector = start >> SECTOR_SHIFT; + sector_t nr_sects = len >> SECTOR_SHIFT; + struct bio *prev = NULL, *bio; + int err; + + if (!bdev_max_discard_sectors(bdev)) + return -EOPNOTSUPP; + + 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; + + /* + * 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 > bio_discard_limit(bdev, sector)) + return -EAGAIN; + + err = filemap_invalidate_pages(bdev->bd_mapping, start, + start + len - 1, nowait); + if (err) + return err; + + while ((bio = blk_alloc_discard_bio(bdev, §or, &nr_sects, gfp))) { + if (nowait) + bio->bi_opf |= REQ_NOWAIT; + prev = bio_chain_and_submit(prev, bio); + } + if (!prev) + return -EAGAIN; + + prev->bi_private = cmd; + prev->bi_end_io = bio_cmd_bio_end_io; + submit_bio(prev); + return -EIOCBQUEUED; +} + +int blkdev_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) +{ + struct block_device *bdev = I_BDEV(cmd->file->f_mapping->host); + struct blk_iou_cmd *bic = io_uring_cmd_to_pdu(cmd, struct blk_iou_cmd); + const struct io_uring_sqe *sqe = cmd->sqe; + u32 cmd_op = cmd->cmd_op; + uint64_t start, len; + + if (unlikely(sqe->ioprio || sqe->__pad1 || sqe->len || + sqe->rw_flags || sqe->file_index)) + return -EINVAL; + + bic->res = 0; + bic->nowait = issue_flags & IO_URING_F_NONBLOCK; + + start = READ_ONCE(sqe->addr); + len = READ_ONCE(sqe->addr3); + + switch (cmd_op) { + case BLOCK_URING_CMD_DISCARD: + return blkdev_cmd_discard(cmd, bdev, start, len, bic->nowait); + } + return -EINVAL; +} diff --git a/include/linux/bio.h b/include/linux/bio.h index faceadb040f9..78ead424484c 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -684,4 +684,6 @@ struct bio *bio_chain_and_submit(struct bio *prev, struct bio *new); struct bio *blk_alloc_discard_bio(struct block_device *bdev, sector_t *sector, sector_t *nr_sects, gfp_t gfp_mask); +sector_t bio_discard_limit(struct block_device *bdev, sector_t sector); + #endif /* __LINUX_BIO_H */ diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 753971770733..7ea41ca97158 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -208,6 +208,8 @@ struct fsxattr { * (see uapi/linux/blkzoned.h) */ +#define BLOCK_URING_CMD_DISCARD _IO(0x12,137) + #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */