Re: git: 6d408ac49073 - main - fusefs: add a regression test for a cluster_read bug
Date: Fri, 24 Oct 2025 08:12:49 UTC
On Thu, Oct 23, 2025 at 01:41:05PM +0000, Alan Somers wrote:
> The branch main has been updated by asomers:
>
> URL: https://cgit.FreeBSD.org/src/commit/?id=6d408ac490730614b3ed0ebd3caffcd23f303fb4
>
> commit 6d408ac490730614b3ed0ebd3caffcd23f303fb4
> Author: Alan Somers <asomers@FreeBSD.org>
> AuthorDate: 2025-10-23 13:40:56 +0000
> Commit: Alan Somers <asomers@FreeBSD.org>
> CommitDate: 2025-10-23 13:40:56 +0000
>
> fusefs: add a regression test for a cluster_read bug
>
> VOP_BMAP is purely advisory. If VOP_BMAP returns an error during
> readahead, cluster_read should still succeed, because the actual data
> was still read just fine.
No, VOP_BMAP() is not advisory. But read-ahead beyond the first buffer is.
The BMAP in question is to translate lblk for read-ahead buffer.
>
> Add a regression test for PR 264196, wherein cluster_read would fail if
> VOP_BMAP did.
>
> PR: 264196
> MFC with: 62aef3f73f38db9fb68bffc12cc8900fecd58f0e
> Reported by: danfe
> Reviewed by: arrowd
> Differential Revision: https://reviews.freebsd.org/D51316
> ---
> tests/sys/fs/fusefs/bmap.cc | 87 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 87 insertions(+)
>
> diff --git a/tests/sys/fs/fusefs/bmap.cc b/tests/sys/fs/fusefs/bmap.cc
> index 30612079657d..e61dadb6d79e 100644
> --- a/tests/sys/fs/fusefs/bmap.cc
> +++ b/tests/sys/fs/fusefs/bmap.cc
> @@ -177,6 +177,93 @@ TEST_F(Bmap, default_)
> leak(fd);
> }
>
> +/*
> + * The server returns an error for some reason for FUSE_BMAP. fusefs should
> + * faithfully report that error up to the caller.
> + */
> +TEST_F(Bmap, einval)
> +{
> + struct fiobmap2_arg arg;
> + const off_t filesize = 1 << 30;
> + int64_t lbn = 100;
> + const ino_t ino = 42;
> + int fd;
> +
> + expect_lookup(RELPATH, 42, filesize);
> + expect_open(ino, 0, 1);
> + EXPECT_CALL(*m_mock, process(
> + ResultOf([=](auto in) {
> + return (in.header.opcode == FUSE_BMAP &&
> + in.header.nodeid == ino);
> + }, Eq(true)),
> + _)
> + ).WillOnce(Invoke(ReturnErrno(EINVAL)));
> +
> + fd = open(FULLPATH, O_RDWR);
> + ASSERT_LE(0, fd) << strerror(errno);
> +
> + arg.bn = lbn;
> + arg.runp = -1;
> + arg.runb = -1;
> + ASSERT_EQ(-1, ioctl(fd, FIOBMAP2, &arg));
> + EXPECT_EQ(EINVAL, errno);
> +
> + leak(fd);
> +}
> +
> +/*
> + * Even if the server returns EINVAL during VOP_BMAP, we should still be able
> + * to successfully read a block. This is a regression test for
> + * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=264196 . The bug did not
> + * lie in fusefs, but this is a convenient place for a regression test.
> + */
> +TEST_F(Bmap, spurious_einval)
> +{
> + const off_t filesize = 4ull << 30;
> + const ino_t ino = 42;
> + int fd, r;
> + char buf[1];
> +
> + expect_lookup(RELPATH, 42, filesize);
> + expect_open(ino, 0, 1);
> + EXPECT_CALL(*m_mock, process(
> + ResultOf([=](auto in) {
> + return (in.header.opcode == FUSE_BMAP &&
> + in.header.nodeid == ino);
> + }, Eq(true)),
> + _)
> + ).WillRepeatedly(Invoke(ReturnErrno(EINVAL)));
> + EXPECT_CALL(*m_mock, process(
> + ResultOf([=](auto in) {
> + return (in.header.opcode == FUSE_READ &&
> + in.header.nodeid == ino &&
> + in.body.read.offset == 0 &&
> + in.body.read.size == (uint64_t)m_maxbcachebuf);
> + }, Eq(true)),
> + _)
> + ).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) {
> + size_t osize = in.body.read.size;
> +
> + assert(osize < sizeof(out.body.bytes));
> + out.header.len = sizeof(struct fuse_out_header) + osize;
> + bzero(out.body.bytes, osize);
> + })));
> +
> + fd = open(FULLPATH, O_RDWR);
> + ASSERT_LE(0, fd) << strerror(errno);
> +
> + /*
> + * Read the same block multiple times. On a system affected by PR
> + * 264196 , the second read will fail.
> + */
> + r = read(fd, buf, sizeof(buf));
> + EXPECT_EQ(r, 1) << strerror(errno);
> + r = read(fd, buf, sizeof(buf));
> + EXPECT_EQ(r, 1) << strerror(errno);
> + r = read(fd, buf, sizeof(buf));
> + EXPECT_EQ(r, 1) << strerror(errno);
> +}
> +
> /*
> * VOP_BMAP should not query the server for the file's size, even if its cached
> * attributes have expired.