svn commit: r347358 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs
Alan Somers
asomers at FreeBSD.org
Wed May 8 18:12:40 UTC 2019
Author: asomers
Date: Wed May 8 18:12:38 2019
New Revision: 347358
URL: https://svnweb.freebsd.org/changeset/base/347358
Log:
fusefs: updated cached attributes during VOP_LINK.
FUSE_LINK returns a new set of attributes. fusefs should cache them just
like it does during other VOPs. This is not only a matter of performance
but of correctness too; without caching the new attributes the vnode's nlink
value would be out-of-date.
Reported by: pjdfstest
Sponsored by: The FreeBSD Foundation
Modified:
projects/fuse2/sys/fs/fuse/fuse_vnops.c
projects/fuse2/tests/sys/fs/fusefs/link.cc
projects/fuse2/tests/sys/fs/fusefs/setattr.cc
Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c Wed May 8 18:10:19 2019 (r347357)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Wed May 8 18:12:38 2019 (r347358)
@@ -817,6 +817,9 @@ fuse_vnop_link(struct vop_link_args *ap)
feo = fdi.answ;
err = fuse_internal_checkentry(feo, vnode_vtype(vp));
+ if (!err)
+ fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid,
+ feo->attr_valid_nsec, NULL);
out:
fdisp_destroy(&fdi);
return err;
Modified: projects/fuse2/tests/sys/fs/fusefs/link.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/link.cc Wed May 8 18:10:19 2019 (r347357)
+++ projects/fuse2/tests/sys/fs/fusefs/link.cc Wed May 8 18:12:38 2019 (r347358)
@@ -77,26 +77,41 @@ TEST_F(Link, ok)
const char RELPATH[] = "src";
const char FULLDST[] = "mountpoint/dst";
const char RELDST[] = "dst";
- uint64_t dst_ino = 42;
const uint64_t ino = 42;
+ mode_t mode = S_IFREG | 0644;
+ struct stat sb;
EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
- expect_lookup(RELDST, dst_ino);
+ EXPECT_LOOKUP(1, RELDST)
+ .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, entry);
+ out->body.entry.attr.mode = mode;
+ out->body.entry.nodeid = ino;
+ out->body.entry.attr.nlink = 1;
+ out->body.entry.attr_valid = UINT64_MAX;
+ out->body.entry.entry_valid = UINT64_MAX;
+ })));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in->body.bytes
+ sizeof(struct fuse_link_in);
return (in->header.opcode == FUSE_LINK &&
- in->body.link.oldnodeid == dst_ino &&
+ in->body.link.oldnodeid == ino &&
(0 == strcmp(name, RELPATH)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
SET_OUT_HEADER_LEN(out, entry);
- out->body.entry.attr.mode = S_IFREG | 0644;
+ out->body.entry.attr.mode = mode;
out->body.entry.nodeid = ino;
+ out->body.entry.attr.nlink = 2;
+ out->body.entry.attr_valid = UINT64_MAX;
+ out->body.entry.entry_valid = UINT64_MAX;
})));
- EXPECT_EQ(0, link(FULLDST, FULLPATH)) << strerror(errno);
+ ASSERT_EQ(0, link(FULLDST, FULLPATH)) << strerror(errno);
+ // Check that the original file's nlink count has increased.
+ ASSERT_EQ(0, stat(FULLDST, &sb)) << strerror(errno);
+ EXPECT_EQ(2ul, sb.st_nlink);
}
Modified: projects/fuse2/tests/sys/fs/fusefs/setattr.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/setattr.cc Wed May 8 18:10:19 2019 (r347357)
+++ projects/fuse2/tests/sys/fs/fusefs/setattr.cc Wed May 8 18:12:38 2019 (r347358)
@@ -131,6 +131,70 @@ TEST_F(Setattr, chmod)
EXPECT_EQ(0, chmod(FULLPATH, newmode)) << strerror(errno);
}
+/*
+ * Chmod a multiply-linked file with cached attributes. Check that both files'
+ * attributes have changed.
+ */
+TEST_F(Setattr, chmod_multiply_linked)
+{
+ const char FULLPATH0[] = "mountpoint/some_file.txt";
+ const char RELPATH0[] = "some_file.txt";
+ const char FULLPATH1[] = "mountpoint/other_file.txt";
+ const char RELPATH1[] = "other_file.txt";
+ struct stat sb;
+ const uint64_t ino = 42;
+ const mode_t oldmode = 0777;
+ const mode_t newmode = 0666;
+
+ EXPECT_LOOKUP(1, RELPATH0)
+ .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, entry);
+ out->body.entry.attr.mode = S_IFREG | oldmode;
+ out->body.entry.nodeid = ino;
+ out->body.entry.attr.nlink = 2;
+ out->body.entry.attr_valid = UINT64_MAX;
+ out->body.entry.entry_valid = UINT64_MAX;
+ })));
+
+ EXPECT_LOOKUP(1, RELPATH1)
+ .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, entry);
+ out->body.entry.attr.mode = S_IFREG | oldmode;
+ out->body.entry.nodeid = ino;
+ out->body.entry.attr.nlink = 2;
+ out->body.entry.attr_valid = UINT64_MAX;
+ out->body.entry.entry_valid = UINT64_MAX;
+ })));
+
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([](auto in) {
+ uint32_t valid = FATTR_MODE;
+ return (in->header.opcode == FUSE_SETATTR &&
+ in->header.nodeid == ino &&
+ in->body.setattr.valid == valid &&
+ in->body.setattr.mode == newmode);
+ }, Eq(true)),
+ _)
+ ).WillOnce(Invoke(ReturnImmediate([](auto in __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, attr);
+ out->body.attr.attr.ino = ino;
+ out->body.attr.attr.mode = S_IFREG | newmode;
+ out->body.attr.attr.nlink = 2;
+ out->body.attr.attr_valid = UINT64_MAX;
+ })));
+
+ /* For a lookup of the 2nd file to get it into the cache*/
+ ASSERT_EQ(0, stat(FULLPATH1, &sb)) << strerror(errno);
+ EXPECT_EQ(S_IFREG | oldmode, sb.st_mode);
+
+ ASSERT_EQ(0, chmod(FULLPATH0, newmode)) << strerror(errno);
+ ASSERT_EQ(0, stat(FULLPATH0, &sb)) << strerror(errno);
+ EXPECT_EQ(S_IFREG | newmode, sb.st_mode);
+ ASSERT_EQ(0, stat(FULLPATH1, &sb)) << strerror(errno);
+ EXPECT_EQ(S_IFREG | newmode, sb.st_mode);
+}
+
+
/* Change the owner and group of a file */
TEST_F(Setattr, chown)
{
More information about the svn-src-projects
mailing list