From: Zhang Yi <yi.zhang@huawei.com>
To: <linux-ext4@vger.kernel.org>, <linux-fsdevel@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <cluster-devel@redhat.com>,
<ntfs3@lists.linux.dev>, <ocfs2-devel@oss.oracle.com>,
<reiserfs-devel@vger.kernel.org>
Cc: <jack@suse.cz>, <tytso@mit.edu>, <akpm@linux-foundation.org>,
<axboe@kernel.dk>, <viro@zeniv.linux.org.uk>,
<rpeterso@redhat.com>, <agruenba@redhat.com>,
<almaz.alexandrovich@paragon-software.com>, <mark@fasheh.com>,
<dushistov@mail.ru>, <hch@infradead.org>, <yi.zhang@huawei.com>,
<chengzhihao1@huawei.com>, <yukuai3@huawei.com>
Subject: [PATCH 02/14] fs/buffer: add some new buffer read helpers
Date: Wed, 31 Aug 2022 15:20:59 +0800 [thread overview]
Message-ID: <20220831072111.3569680-3-yi.zhang@huawei.com> (raw)
In-Reply-To: <20220831072111.3569680-1-yi.zhang@huawei.com>
Current ll_rw_block() helper is fragile because it assumes that locked
buffer means it's under IO which is submitted by some other who hold
the lock, it skip buffer if it failed to get the lock, so it's only
safe on the readahead path. Unfortunately, now that most filesystems
still use this helper mistakenly on the sync metadata read path. There
is no guarantee that the one who hold the buffer lock always submit IO
(e.g. buffer_migrate_folio_norefs() after commit 88dbcbb3a484 ("blkdev:
avoid migration stalls for blkdev pages"), it could lead to false
positive -EIO when submitting reading IO.
This patch add some friendly buffer read helpers to prepare replace
ll_rw_block() and similar calls. We can only call bh_readahead_[]
helpers for the readahead paths.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
---
fs/buffer.c | 68 +++++++++++++++++++++++++++++++++++++
include/linux/buffer_head.h | 37 ++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/fs/buffer.c b/fs/buffer.c
index a0b70b3239f3..a663191903ed 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -3017,6 +3017,74 @@ int bh_uptodate_or_lock(struct buffer_head *bh)
}
EXPORT_SYMBOL(bh_uptodate_or_lock);
+/**
+ * __bh_read - Submit read for a locked buffer
+ * @bh: struct buffer_head
+ * @op_flags: appending REQ_OP_* flags besides REQ_OP_READ
+ * @wait: wait until reading finish
+ *
+ * Returns zero on success or don't wait, and -EIO on error.
+ */
+int __bh_read(struct buffer_head *bh, blk_opf_t op_flags, bool wait)
+{
+ int ret = 0;
+
+ BUG_ON(!buffer_locked(bh));
+
+ if (buffer_uptodate(bh)) {
+ unlock_buffer(bh);
+ return ret;
+ }
+
+ get_bh(bh);
+ bh->b_end_io = end_buffer_read_sync;
+ submit_bh(REQ_OP_READ | op_flags, bh);
+ if (wait) {
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ ret = -EIO;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(__bh_read);
+
+/**
+ * __bh_read_batch - Submit read for a batch of unlocked buffers
+ * @bhs: a batch of struct buffer_head
+ * @nr: number of this batch
+ * @op_flags: appending REQ_OP_* flags besides REQ_OP_READ
+ * @force_lock: force to get a lock on the buffer if set, otherwise drops any
+ * buffer that cannot lock.
+ *
+ * Returns zero on success or don't wait, and -EIO on error.
+ */
+void __bh_read_batch(struct buffer_head *bhs[],
+ int nr, blk_opf_t op_flags, bool force_lock)
+{
+ int i;
+
+ for (i = 0; i < nr; i++) {
+ struct buffer_head *bh = bhs[i];
+
+ if (buffer_uptodate(bh))
+ continue;
+ if (!trylock_buffer(bh)) {
+ if (!force_lock)
+ continue;
+ lock_buffer(bh);
+ }
+ if (buffer_uptodate(bh)) {
+ unlock_buffer(bh);
+ continue;
+ }
+
+ bh->b_end_io = end_buffer_read_sync;
+ get_bh(bh);
+ submit_bh(REQ_OP_READ | op_flags, bh);
+ }
+}
+EXPORT_SYMBOL(__bh_read_batch);
+
/**
* bh_submit_read - Submit a locked buffer for reading
* @bh: struct buffer_head
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index c3863c417b00..8a01c07c0418 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -232,6 +232,9 @@ void write_boundary_block(struct block_device *bdev,
sector_t bblock, unsigned blocksize);
int bh_uptodate_or_lock(struct buffer_head *bh);
int bh_submit_read(struct buffer_head *bh);
+int __bh_read(struct buffer_head *bh, blk_opf_t op_flags, bool wait);
+void __bh_read_batch(struct buffer_head *bhs[],
+ int nr, blk_opf_t op_flags, bool force_lock);
extern int buffer_heads_over_limit;
@@ -399,6 +402,40 @@ static inline struct buffer_head *__getblk(struct block_device *bdev,
return __getblk_gfp(bdev, block, size, __GFP_MOVABLE);
}
+static inline void bh_readahead(struct buffer_head *bh, blk_opf_t op_flags)
+{
+ if (trylock_buffer(bh))
+ __bh_read(bh, op_flags, false);
+}
+
+static inline void bh_read_nowait(struct buffer_head *bh, blk_opf_t op_flags)
+{
+ lock_buffer(bh);
+ __bh_read(bh, op_flags, false);
+}
+
+static inline int bh_read(struct buffer_head *bh, blk_opf_t op_flags)
+{
+ lock_buffer(bh);
+ return __bh_read(bh, op_flags, true);
+}
+
+static inline int bh_read_locked(struct buffer_head *bh, blk_opf_t op_flags)
+{
+ return __bh_read(bh, op_flags, true);
+}
+
+static inline void bh_read_batch(struct buffer_head *bhs[], int nr)
+{
+ __bh_read_batch(bhs, nr, 0, true);
+}
+
+static inline void bh_readahead_batch(struct buffer_head *bhs[], int nr,
+ blk_opf_t op_flags)
+{
+ __bh_read_batch(bhs, nr, op_flags, false);
+}
+
/**
* __bread() - reads a specified block and returns the bh
* @bdev: the block_device to read from
--
2.31.1
next prev parent reply other threads:[~2022-08-31 7:10 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-31 7:20 [PATCH 00/14] buffer: remove ll_rw_block() Zhang Yi
2022-08-31 7:20 ` [PATCH 01/14] fs/buffer: remove __breadahead_gfp() Zhang Yi
2022-08-31 10:39 ` Jan Kara
2022-08-31 7:20 ` Zhang Yi [this message]
2022-08-31 11:30 ` [PATCH 02/14] fs/buffer: add some new buffer read helpers Jan Kara
2022-08-31 13:11 ` Zhang Yi
2022-08-31 7:21 ` [PATCH 03/14] fs/buffer: replace ll_rw_block() Zhang Yi
2022-08-31 10:51 ` Jan Kara
2022-08-31 7:21 ` [PATCH 04/14] gfs2: " Zhang Yi
2022-08-31 10:52 ` Jan Kara
2022-08-31 7:21 ` [PATCH 05/14] isofs: " Zhang Yi
2022-08-31 10:53 ` Jan Kara
2022-08-31 7:21 ` [PATCH 06/14] jbd2: " Zhang Yi
2022-08-31 10:58 ` Jan Kara
2022-08-31 7:21 ` [PATCH 07/14] ntfs3: " Zhang Yi
2022-08-31 10:59 ` Jan Kara
2022-08-31 7:21 ` [PATCH 08/14] ocfs2: " Zhang Yi
2022-08-31 11:31 ` Jan Kara
2022-08-31 7:21 ` [PATCH 09/14] reiserfs: " Zhang Yi
2022-08-31 11:04 ` Jan Kara
2022-08-31 7:21 ` [PATCH 10/14] udf: " Zhang Yi
2022-08-31 11:05 ` Jan Kara
2022-08-31 7:21 ` [PATCH 11/14] ufs: " Zhang Yi
2022-08-31 11:06 ` Jan Kara
2022-08-31 7:21 ` [PATCH 12/14] fs/buffer: remove ll_rw_block() helper Zhang Yi
2022-08-31 11:06 ` Jan Kara
2022-08-31 7:21 ` [PATCH 13/14] ext2: replace bh_submit_read() helper with bh_read_locked() Zhang Yi
2022-08-31 11:15 ` Jan Kara
2022-08-31 7:21 ` [PATCH 14/14] fs/buffer: remove bh_submit_read() helper Zhang Yi
2022-08-31 11:16 ` Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220831072111.3569680-3-yi.zhang@huawei.com \
--to=yi.zhang@huawei.com \
--cc=agruenba@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=almaz.alexandrovich@paragon-software.com \
--cc=axboe@kernel.dk \
--cc=chengzhihao1@huawei.com \
--cc=cluster-devel@redhat.com \
--cc=dushistov@mail.ru \
--cc=hch@infradead.org \
--cc=jack@suse.cz \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mark@fasheh.com \
--cc=ntfs3@lists.linux.dev \
--cc=ocfs2-devel@oss.oracle.com \
--cc=reiserfs-devel@vger.kernel.org \
--cc=rpeterso@redhat.com \
--cc=tytso@mit.edu \
--cc=viro@zeniv.linux.org.uk \
--cc=yukuai3@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).