git: e8553be9bcfc - main - fusefs: fix a cached attributes bug during directory rename
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 24 Feb 2022 21:07:43 UTC
The branch main has been updated by asomers:
URL: https://cgit.FreeBSD.org/src/commit/?id=e8553be9bcfc2c0d78e9f379bd166dc0a9cae719
commit e8553be9bcfc2c0d78e9f379bd166dc0a9cae719
Author: Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2022-02-22 05:00:42 +0000
Commit: Alan Somers <asomers@FreeBSD.org>
CommitDate: 2022-02-24 21:07:25 +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.
MFC after: 1 week
Reviewed by: ngie
Differential Revision: https://reviews.freebsd.org/D34336
---
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 3de44bf6a023..c7730cf7c606 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2084,7 +2084,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);
}