The branch stable/13 has been updated by asomers:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=79ec7ebf88ef86ffbb89ddb84ba2881b2f318529

commit 79ec7ebf88ef86ffbb89ddb84ba2881b2f318529
Author:     Alan Somers <asom...@freebsd.org>
AuthorDate: 2022-02-22 05:00:42 +0000
Commit:     Alan Somers <asom...@freebsd.org>
CommitDate: 2022-03-09 16:59:49 +0000

    fusefs: fix a cached attributes bug during directory rename
    
    When renaming a directory into a different parent directory, invalidate
    the cached attributes of the new parent.  Otherwise, stat will show the
    wrong st_nlink value.
    
    Reviewed by:    ngie
    Differential Revision: https://reviews.freebsd.org/D34336
    
    (cherry picked from commit e8553be9bcfc2c0d78e9f379bd166dc0a9cae719)
---
 sys/fs/fuse/fuse_vnops.c      |  2 +-
 tests/sys/fs/fusefs/rename.cc | 38 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index 7a3417749b72..f95ee1b7f6b3 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2085,7 +2085,7 @@ fuse_vnop_rename(struct vop_rename_args *ap)
                cache_purge(tvp);
        }
        if (vnode_isdir(fvp)) {
-               if ((tvp != NULL) && vnode_isdir(tvp)) {
+               if (((tvp != NULL) && vnode_isdir(tvp)) || vnode_isdir(fvp)) {
                        cache_purge(tdvp);
                }
                cache_purge(fdvp);
diff --git a/tests/sys/fs/fusefs/rename.cc b/tests/sys/fs/fusefs/rename.cc
index ba1d5ec1ec6d..23d25c9965bf 100644
--- a/tests/sys/fs/fusefs/rename.cc
+++ b/tests/sys/fs/fusefs/rename.cc
@@ -221,7 +221,8 @@ TEST_F(Rename, parent)
        const char RELDST[] = "dst";
        const char FULLSRC[] = "mountpoint/src";
        const char RELSRC[] = "src";
-       const char FULLDSTPARENT[] = "mountpoint/dstdir/dst/..";
+       const char FULLDSTPARENT[] = "mountpoint/dstdir";
+       const char FULLDSTDOTDOT[] = "mountpoint/dstdir/dst/..";
        Sequence seq;
        uint64_t dst_dir_ino = 43;
        uint64_t ino = 42;
@@ -229,13 +230,14 @@ TEST_F(Rename, parent)
 
        expect_lookup(RELSRC, ino, S_IFDIR | 0755, 0, 1);
        EXPECT_LOOKUP(FUSE_ROOT_ID, RELDSTDIR)
-       .WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) 
{
+       .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
                SET_OUT_HEADER_LEN(out, entry);
                out.body.entry.nodeid = dst_dir_ino;
                out.body.entry.entry_valid = UINT64_MAX;
                out.body.entry.attr_valid = UINT64_MAX;
                out.body.entry.attr.mode = S_IFDIR | 0755;
                out.body.entry.attr.ino = dst_dir_ino;
+               out.body.entry.attr.nlink = 2;
        })));
        EXPECT_LOOKUP(dst_dir_ino, RELDST)
        .InSequence(seq)
@@ -252,6 +254,31 @@ TEST_F(Rename, parent)
                }, Eq(true)),
                _)
        ).WillOnce(Invoke(ReturnErrno(0)));
+       EXPECT_CALL(*m_mock, process(
+               ResultOf([](auto in) {
+                       return (in.header.opcode == FUSE_GETATTR &&
+                               in.header.nodeid == 1);
+               }, Eq(true)),
+               _)
+       ).InSequence(seq)
+       .WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
+               SET_OUT_HEADER_LEN(out, attr);
+               out.body.attr.attr_valid = UINT64_MAX;
+               out.body.attr.attr.ino = 1;
+               out.body.attr.attr.mode = S_IFDIR | 0755;
+               out.body.attr.attr.nlink = 2;
+       })));
+       EXPECT_LOOKUP(FUSE_ROOT_ID, RELDSTDIR)
+       .InSequence(seq)
+       .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
+               SET_OUT_HEADER_LEN(out, entry);
+               out.body.entry.nodeid = dst_dir_ino;
+               out.body.entry.entry_valid = UINT64_MAX;
+               out.body.entry.attr_valid = UINT64_MAX;
+               out.body.entry.attr.mode = S_IFDIR | 0755;
+               out.body.entry.attr.ino = dst_dir_ino;
+               out.body.entry.attr.nlink = 3;
+       })));
        EXPECT_LOOKUP(dst_dir_ino, RELDST)
        .InSequence(seq)
        .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
@@ -263,7 +290,14 @@ TEST_F(Rename, parent)
        })));
 
        ASSERT_EQ(0, rename(FULLSRC, FULLDST)) << strerror(errno);
+
+       ASSERT_EQ(0, stat("mountpoint", &sb)) << strerror(errno);
+       EXPECT_EQ(2ul, sb.st_nlink);
+
        ASSERT_EQ(0, stat(FULLDSTPARENT, &sb)) << strerror(errno);
+       EXPECT_EQ(3ul, sb.st_nlink);
+
+       ASSERT_EQ(0, stat(FULLDSTDOTDOT, &sb)) << strerror(errno);
        ASSERT_EQ(dst_dir_ino, sb.st_ino);
 }
 

Reply via email to