From: Andreas Gruenbacher <agruenba@redhat.com> To: Christoph Hellwig <hch@lst.de>, "Darrick J . Wong" <djwong@kernel.org> Cc: linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, cluster-devel@redhat.com, Andreas Gruenbacher <agruenba@redhat.com>, stable@vger.kernel.org Subject: [5.15 REGRESSION] iomap: Fix inline extent handling in iomap_readpage Date: Wed, 10 Nov 2021 12:38:42 +0100 [thread overview] Message-ID: <20211110113842.517426-1-agruenba@redhat.com> (raw) When reporting IOMAP_INLINE extents, filesystems set iomap->length to the length of iomap->inline_data. For reading that into the page cache, function iomap_read_inline_data copies the inline data, zeroes out the rest of the page, and marks the entire page up-to-date. Before commit 740499c78408 ("iomap: fix the iomap_readpage_actor return value for inline data"), when hitting an IOMAP_INLINE extent, iomap_readpage_actor would report having read the entire page. Since then, it only reports having read the inline data (iomap->length). This will force iomap_readpage into another iteration, and the filesystem will report an unaligned hole after the IOMAP_INLINE extent. But iomap_readpage_actor (now iomap_readpage_iter) isn't prepared to deal with unaligned extents, it will get things wrong on filesystems with a block size smaller than the page size, and we'll eventually run into the following warning in iomap_iter_advance: WARN_ON_ONCE(iter->processed > iomap_length(iter)); Fix that by changing iomap_readpage_iter back to report that we've read the entire page, which avoids having to deal with unaligned extents. To prevent iomap from complaining about running past the end of the extent, fix up the extent size as well. Fixes: 740499c78408 ("iomap: fix the iomap_readpage_actor return value for inline data") Cc: stable@vger.kernel.org # v5.15+ Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> --- fs/iomap/buffered-io.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 1753c26c8e76..de3fcd2522a2 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -244,10 +244,10 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter, pos >= i_size_read(iter->inode); } -static loff_t iomap_readpage_iter(const struct iomap_iter *iter, +static loff_t iomap_readpage_iter(struct iomap_iter *iter, struct iomap_readpage_ctx *ctx, loff_t offset) { - const struct iomap *iomap = &iter->iomap; + struct iomap *iomap = &iter->iomap; loff_t pos = iter->pos + offset; loff_t length = iomap_length(iter) - offset; struct page *page = ctx->cur_page; @@ -256,8 +256,15 @@ static loff_t iomap_readpage_iter(const struct iomap_iter *iter, unsigned poff, plen; sector_t sector; - if (iomap->type == IOMAP_INLINE) - return min(iomap_read_inline_data(iter, page), length); + if (iomap->type == IOMAP_INLINE) { + /* + * The filesystem sets iomap->length to the size of the inline + * data. We're at the end of the file, so we know that the + * rest of the page needs to be zeroed out. + */ + iomap->length = iomap_read_inline_data(iter, page); + return iomap->length; + } /* zero post-eof blocks as the page may be mapped */ iop = iomap_page_create(iter->inode, page); @@ -352,7 +359,7 @@ iomap_readpage(struct page *page, const struct iomap_ops *ops) } EXPORT_SYMBOL_GPL(iomap_readpage); -static loff_t iomap_readahead_iter(const struct iomap_iter *iter, +static loff_t iomap_readahead_iter(struct iomap_iter *iter, struct iomap_readpage_ctx *ctx) { loff_t length = iomap_length(iter); -- 2.31.1
WARNING: multiple messages have this Message-ID (diff)
From: Andreas Gruenbacher <agruenba@redhat.com> To: cluster-devel.redhat.com Subject: [Cluster-devel] [5.15 REGRESSION] iomap: Fix inline extent handling in iomap_readpage Date: Wed, 10 Nov 2021 12:38:42 +0100 [thread overview] Message-ID: <20211110113842.517426-1-agruenba@redhat.com> (raw) When reporting IOMAP_INLINE extents, filesystems set iomap->length to the length of iomap->inline_data. For reading that into the page cache, function iomap_read_inline_data copies the inline data, zeroes out the rest of the page, and marks the entire page up-to-date. Before commit 740499c78408 ("iomap: fix the iomap_readpage_actor return value for inline data"), when hitting an IOMAP_INLINE extent, iomap_readpage_actor would report having read the entire page. Since then, it only reports having read the inline data (iomap->length). This will force iomap_readpage into another iteration, and the filesystem will report an unaligned hole after the IOMAP_INLINE extent. But iomap_readpage_actor (now iomap_readpage_iter) isn't prepared to deal with unaligned extents, it will get things wrong on filesystems with a block size smaller than the page size, and we'll eventually run into the following warning in iomap_iter_advance: WARN_ON_ONCE(iter->processed > iomap_length(iter)); Fix that by changing iomap_readpage_iter back to report that we've read the entire page, which avoids having to deal with unaligned extents. To prevent iomap from complaining about running past the end of the extent, fix up the extent size as well. Fixes: 740499c78408 ("iomap: fix the iomap_readpage_actor return value for inline data") Cc: stable at vger.kernel.org # v5.15+ Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> --- fs/iomap/buffered-io.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 1753c26c8e76..de3fcd2522a2 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -244,10 +244,10 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter, pos >= i_size_read(iter->inode); } -static loff_t iomap_readpage_iter(const struct iomap_iter *iter, +static loff_t iomap_readpage_iter(struct iomap_iter *iter, struct iomap_readpage_ctx *ctx, loff_t offset) { - const struct iomap *iomap = &iter->iomap; + struct iomap *iomap = &iter->iomap; loff_t pos = iter->pos + offset; loff_t length = iomap_length(iter) - offset; struct page *page = ctx->cur_page; @@ -256,8 +256,15 @@ static loff_t iomap_readpage_iter(const struct iomap_iter *iter, unsigned poff, plen; sector_t sector; - if (iomap->type == IOMAP_INLINE) - return min(iomap_read_inline_data(iter, page), length); + if (iomap->type == IOMAP_INLINE) { + /* + * The filesystem sets iomap->length to the size of the inline + * data. We're at the end of the file, so we know that the + * rest of the page needs to be zeroed out. + */ + iomap->length = iomap_read_inline_data(iter, page); + return iomap->length; + } /* zero post-eof blocks as the page may be mapped */ iop = iomap_page_create(iter->inode, page); @@ -352,7 +359,7 @@ iomap_readpage(struct page *page, const struct iomap_ops *ops) } EXPORT_SYMBOL_GPL(iomap_readpage); -static loff_t iomap_readahead_iter(const struct iomap_iter *iter, +static loff_t iomap_readahead_iter(struct iomap_iter *iter, struct iomap_readpage_ctx *ctx) { loff_t length = iomap_length(iter); -- 2.31.1
next reply other threads:[~2021-11-10 11:39 UTC|newest] Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-11-10 11:38 Andreas Gruenbacher [this message] 2021-11-10 11:38 ` [Cluster-devel] [5.15 REGRESSION] iomap: Fix inline extent handling in iomap_readpage Andreas Gruenbacher 2021-11-10 12:55 ` Christoph Hellwig 2021-11-10 12:55 ` [Cluster-devel] " Christoph Hellwig 2021-11-10 14:52 ` Andreas Gruenbacher 2021-11-10 14:52 ` [Cluster-devel] " Andreas Gruenbacher 2021-11-11 7:25 ` Christoph Hellwig 2021-11-11 7:25 ` [Cluster-devel] " Christoph Hellwig 2021-11-11 16:21 ` Andreas Grünbacher 2021-11-11 16:21 ` [Cluster-devel] " Andreas Grünbacher
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=20211110113842.517426-1-agruenba@redhat.com \ --to=agruenba@redhat.com \ --cc=cluster-devel@redhat.com \ --cc=djwong@kernel.org \ --cc=hch@lst.de \ --cc=linux-fsdevel@vger.kernel.org \ --cc=linux-xfs@vger.kernel.org \ --cc=stable@vger.kernel.org \ /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: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
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.