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 e8553be9bc
)
This commit is contained in:
parent
c0d9004101
commit
79ec7ebf88
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user