From owner-svn-src-projects@freebsd.org Wed May 8 18:12:40 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 208CE158F947 for ; Wed, 8 May 2019 18:12:40 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id BC3FB87ED6; Wed, 8 May 2019 18:12:39 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7F202977D; Wed, 8 May 2019 18:12:39 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x48ICdkk095258; Wed, 8 May 2019 18:12:39 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x48ICcL1095254; Wed, 8 May 2019 18:12:38 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201905081812.x48ICcL1095254@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Wed, 8 May 2019 18:12:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r347358 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 347358 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: BC3FB87ED6 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.95 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.95)[-0.955,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 May 2019 18:12:40 -0000 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) {