FreeBSD Bugzilla – Attachment 214294 Details for
Bug 245689
Chmod performs unnecessary access calls (FUSE fs)
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Fix issues with FUSE_ACCESS when default_permissions is disabled
pr245689.diff (text/plain), 27.30 KB, created by
Alan Somers
on 2020-05-08 22:46:53 UTC
(
hide
)
Description:
Fix issues with FUSE_ACCESS when default_permissions is disabled
Filename:
MIME Type:
Creator:
Alan Somers
Created:
2020-05-08 22:46:53 UTC
Size:
27.30 KB
patch
obsolete
>Index: sys/fs/fuse/fuse_internal.c >=================================================================== >--- sys/fs/fuse/fuse_internal.c (revision 360828) >+++ sys/fs/fuse/fuse_internal.c (working copy) >@@ -158,6 +158,7 @@ > return 0; > } > >+SDT_PROBE_DEFINE0(fusefs, , internal, access_vadmin); > /* Synchronously send a FUSE_ACCESS operation */ > int > fuse_internal_access(struct vnode *vp, >@@ -213,7 +214,12 @@ > if (!fsess_isimpl(mp, FUSE_ACCESS)) > return 0; > >- if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) >+ if (mode & VADMIN) { >+ // The FUSE protocol doesn't have an equivalent of VADMIN, so >+ // it's a bug if we ever reach this point with that bit set. >+ SDT_PROBE0(fusefs, , internal, access_vadmin); >+ } >+ if ((mode & (VWRITE | VAPPEND)) != 0) > mask |= W_OK; > if ((mode & VREAD) != 0) > mask |= R_OK; >Index: sys/fs/fuse/fuse_vnops.c >=================================================================== >--- sys/fs/fuse/fuse_vnops.c (revision 360614) >+++ sys/fs/fuse/fuse_vnops.c (working copy) >@@ -235,6 +235,7 @@ > { > struct mount *mp = vnode_mount(vp); > struct fuse_data *data = fuse_get_mpdata(mp); >+ int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS; > > /* > * Kernel-invoked always succeeds. >@@ -248,12 +249,16 @@ > */ > switch (ns) { > case EXTATTR_NAMESPACE_SYSTEM: >- if (data->dataflags & FSESS_DEFAULT_PERMISSIONS) { >+ if (default_permissions) { > return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM)); > } > /* FALLTHROUGH */ > case EXTATTR_NAMESPACE_USER: >- return (fuse_internal_access(vp, accmode, td, cred)); >+ if (default_permissions) { >+ return (fuse_internal_access(vp, accmode, td, cred)); >+ } else { >+ return (0); >+ } > default: > return (EPERM); > } >@@ -985,6 +990,8 @@ > int wantparent = flags & (LOCKPARENT | WANTPARENT); > int islastcn = flags & ISLASTCN; > struct mount *mp = vnode_mount(dvp); >+ struct fuse_data *data = fuse_get_mpdata(mp); >+ int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS; > > int err = 0; > int lookup_err = 0; >@@ -1108,7 +1115,11 @@ > if (lookup_err) { > /* Entry not found */ > if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { >- err = fuse_internal_access(dvp, VWRITE, td, cred); >+ if (default_permissions) >+ err = fuse_internal_access(dvp, VWRITE, td, >+ cred); >+ else >+ err = 0; > if (!err) { > /* > * Set the SAVENAME flag to hold onto the >@@ -1191,7 +1202,7 @@ > &fvdat->entry_cache_timeout); > > if ((nameiop == DELETE || nameiop == RENAME) && >- islastcn) >+ islastcn && default_permissions) > { > struct vattr dvattr; > >@@ -1828,7 +1839,9 @@ > if (vfs_isrdonly(mp)) > return EROFS; > >- err = fuse_internal_access(vp, accmode, td, cred); >+ if (data->dataflags & FSESS_DEFAULT_PERMISSIONS) { >+ err = fuse_internal_access(vp, accmode, td, cred); >+ } > if (err) > return err; > else >Index: tests/sys/fs/fusefs/access.cc >=================================================================== >--- tests/sys/fs/fusefs/access.cc (revision 360614) >+++ tests/sys/fs/fusefs/access.cc (working copy) >@@ -31,6 +31,9 @@ > */ > > extern "C" { >+#include <sys/types.h> >+#include <sys/extattr.h> >+ > #include <fcntl.h> > #include <unistd.h> > } >@@ -42,10 +45,33 @@ > > class Access: public FuseTest { > public: >+virtual void SetUp() { >+ FuseTest::SetUp(); >+ // Clear the default FUSE_ACCESS expectation >+ Mock::VerifyAndClearExpectations(m_mock); >+} >+ > void expect_lookup(const char *relpath, uint64_t ino) > { > FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1); > } >+ >+/* >+ * Expect tha FUSE_ACCESS will never be called for the given inode, with any >+ * bits in the supplied access_mask set >+ */ >+void expect_noaccess(uint64_t ino, mode_t access_mask) >+{ >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_ACCESS && >+ in.header.nodeid == ino && >+ in.body.access.mask & access_mask); >+ }, Eq(true)), >+ _) >+ ).Times(0); >+} >+ > }; > > class RofsAccess: public Access { >@@ -56,6 +82,69 @@ > } > }; > >+/* >+ * Change the mode of a file. >+ * >+ * There should never be a FUSE_ACCESS sent for this operation, except possibly >+ * during the lookup phase. >+ * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245689 >+ */ >+TEST_F(Access, chmod) >+{ >+ const char FULLPATH[] = "mountpoint/some_file.txt"; >+ const char RELPATH[] = "some_file.txt"; >+ const uint64_t ino = 42; >+ const mode_t newmode = 0644; >+ >+ expect_access(FUSE_ROOT_ID, X_OK, 0); >+ expect_lookup(RELPATH, ino); >+ expect_noaccess(ino, 0); >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([](auto in) { >+ return (in.header.opcode == FUSE_SETATTR && >+ in.header.nodeid == ino); >+ }, Eq(true)), >+ _) >+ ).WillOnce(Invoke(ReturnImmediate([](auto in __unused, auto& out) { >+ SET_OUT_HEADER_LEN(out, attr); >+ out.body.attr.attr.ino = ino; // Must match nodeid >+ out.body.attr.attr.mode = S_IFREG | newmode; >+ }))); >+ >+ EXPECT_EQ(0, chmod(FULLPATH, newmode)) << strerror(errno); >+} >+ >+/* >+ * Create a new file >+ * >+ * There should never be a FUSE_ACCESS sent for this operation, except for >+ * search permissions on the parent directory. >+ * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245689 >+ */ >+TEST_F(Access, create) >+{ >+ const char FULLPATH[] = "mountpoint/some_file.txt"; >+ const char RELPATH[] = "some_file.txt"; >+ mode_t mode = S_IFREG | 0755; >+ uint64_t ino = 42; >+ >+ expect_access(FUSE_ROOT_ID, X_OK, 0); >+ expect_noaccess(FUSE_ROOT_ID, R_OK | W_OK); >+ //expect_lookup(RELPATH, ino); >+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH) >+ .WillOnce(Invoke(ReturnErrno(ENOENT))); >+ expect_noaccess(ino, 0); >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_CREATE); >+ }, Eq(true)), >+ _) >+ ).WillOnce(ReturnErrno(EPERM)); >+ >+ EXPECT_EQ(-1, open(FULLPATH, O_CREAT | O_EXCL, mode)); >+ EXPECT_EQ(EPERM, errno); >+} >+ > /* The error case of FUSE_ACCESS. */ > TEST_F(Access, eaccess) > { >@@ -105,6 +194,33 @@ > ASSERT_EQ(EROFS, errno); > } > >+ >+/* >+ * Lookup an extended attribute >+ * >+ * There should never be a FUSE_ACCESS sent for this operation, except possibly >+ * during the lookup phase. >+ * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245689 >+ */ >+TEST_F(Access, Getxattr) >+{ >+ const char FULLPATH[] = "mountpoint/some_file.txt"; >+ const char RELPATH[] = "some_file.txt"; >+ uint64_t ino = 42; >+ char data[80]; >+ int ns = EXTATTR_NAMESPACE_USER; >+ ssize_t r; >+ >+ expect_access(FUSE_ROOT_ID, X_OK, 0); >+ expect_lookup(RELPATH, ino); >+ expect_noaccess(ino, 0); >+ expect_getxattr(ino, "user.foo", ReturnErrno(ENOATTR)); >+ >+ r = extattr_get_file(FULLPATH, ns, "foo", data, sizeof(data)); >+ ASSERT_EQ(-1, r); >+ ASSERT_EQ(ENOATTR, errno); >+} >+ > /* The successful case of FUSE_ACCESS. */ > TEST_F(Access, ok) > { >@@ -119,3 +235,70 @@ > > ASSERT_EQ(0, access(FULLPATH, access_mode)) << strerror(errno); > } >+ >+/* >+ * Unlink a file >+ * >+ * There should never be a FUSE_ACCESS sent for this operation, except for >+ * search permissions on the parent directory. >+ * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245689 >+ */ >+TEST_F(Access, unlink) >+{ >+ const char FULLPATH[] = "mountpoint/some_file.txt"; >+ const char RELPATH[] = "some_file.txt"; >+ uint64_t ino = 42; >+ >+ expect_access(FUSE_ROOT_ID, X_OK, 0); >+ expect_noaccess(FUSE_ROOT_ID, W_OK | R_OK); >+ expect_noaccess(ino, 0); >+ expect_lookup(RELPATH, ino); >+ expect_unlink(1, RELPATH, EPERM); >+ >+ ASSERT_NE(0, unlink(FULLPATH)); >+ ASSERT_EQ(EPERM, errno); >+} >+ >+/* >+ * Lookup an extended attribute >+ * >+ * There should never be a FUSE_ACCESS sent for this operation, except possibly >+ * during the lookup phase. >+ * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245689 >+ */ >+TEST_F(Access, unlink_sticky_directory) >+{ >+ const char FULLPATH[] = "mountpoint/some_file.txt"; >+ const char RELPATH[] = "some_file.txt"; >+ uint64_t ino = 42; >+ >+ expect_access(FUSE_ROOT_ID, X_OK, 0); >+ expect_noaccess(FUSE_ROOT_ID, W_OK | R_OK); >+ expect_noaccess(ino, 0); >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_GETATTR && >+ in.header.nodeid == FUSE_ROOT_ID); >+ }, Eq(true)), >+ _) >+ ).WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) >+ { >+ SET_OUT_HEADER_LEN(out, attr); >+ out.body.attr.attr.ino = FUSE_ROOT_ID; >+ out.body.attr.attr.mode = S_IFDIR | 01777; >+ out.body.attr.attr.uid = 0; >+ out.body.attr.attr_valid = UINT64_MAX; >+ }))); >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_ACCESS && >+ in.header.nodeid == ino); >+ }, Eq(true)), >+ _) >+ ).Times(0); >+ expect_lookup(RELPATH, ino); >+ expect_unlink(FUSE_ROOT_ID, RELPATH, EPERM); >+ >+ ASSERT_EQ(-1, unlink(FULLPATH)); >+ ASSERT_EQ(EPERM, errno); >+} >Index: tests/sys/fs/fusefs/default_permissions.cc >=================================================================== >--- tests/sys/fs/fusefs/default_permissions.cc (revision 360614) >+++ tests/sys/fs/fusefs/default_permissions.cc (working copy) >@@ -125,7 +125,7 @@ > out.body.attr.attr.mode = mode; > out.body.attr.attr.size = 0; > out.body.attr.attr.uid = uid; >- out.body.attr.attr.uid = gid; >+ out.body.attr.attr.gid = gid; > out.body.attr.attr_valid = attr_valid; > }))); > } >Index: tests/sys/fs/fusefs/lookup.cc >=================================================================== >--- tests/sys/fs/fusefs/lookup.cc (revision 360614) >+++ tests/sys/fs/fusefs/lookup.cc (working copy) >@@ -39,7 +39,31 @@ > > using namespace testing; > >-class Lookup: public FuseTest {}; >+class Lookup: public FuseTest { >+public: >+/* >+ * Expect a getattr of the mountpoint that may or may not happen. It usually >+ * doesn't, but it can, for example when mac_bsdextended.ko is loaded and >+ * active. In any case, it's allowed >+ */ >+void maybe_expect_getattr() >+{ >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_GETATTR && >+ in.header.nodeid == 1); >+ }, Eq(true)), >+ _) >+ ).Times(AtMost(1)) >+ .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { >+ SET_OUT_HEADER_LEN(out, attr); >+ out.body.attr.attr.ino = 1; >+ out.body.attr.attr.mode = S_IFDIR | 0755; >+ out.body.attr.attr_valid = UINT64_MAX; >+ }))); >+} >+}; >+ > class Lookup_7_8: public Lookup { > public: > virtual void SetUp() { >@@ -301,6 +325,7 @@ > const char FULLPATH[] = "mountpoint/some_file.txt"; > const char RELPATH[] = "some_file.txt"; > >+ //maybe_expect_getattr(); > EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH) > .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { > SET_OUT_HEADER_LEN(out, entry); >Index: tests/sys/fs/fusefs/notify.cc >=================================================================== >--- tests/sys/fs/fusefs/notify.cc (revision 360614) >+++ tests/sys/fs/fusefs/notify.cc (working copy) >@@ -323,12 +323,13 @@ > EXPECT_EQ(0, (intptr_t)thr0_value); > } > >-TEST_F(Notify, inval_inode_with_clean_cache) >+/* Invalidate I/O in the pattern generated by cephfs */ >+TEST_F(Notify, inval_inode_like_cephfs) > { > const static char FULLPATH[] = "mountpoint/foo"; > const static char RELPATH[] = "foo"; >- const char CONTENTS0[] = "abcdefgh"; >- const char CONTENTS1[] = "ijklmnopqrstuvwxyz"; >+ const char CONTENTS0[] = "0123456789"; >+ const char CONTENTS1[] = "0123456789Singapore"; > struct inval_inode_args iia; > struct stat sb; > ino_t ino = 42; >@@ -343,6 +344,25 @@ > > expect_lookup(FUSE_ROOT_ID, RELPATH, ino, size0, seq); > expect_open(ino, 0, 1); >+ expect_read(ino, 0, size0, size0, CONTENTS0); >+ >+ /* Fill the data cache */ >+ fd = open(FULLPATH, O_RDWR); >+ ASSERT_LE(0, fd) << strerror(errno); >+ ASSERT_EQ(size0, read(fd, buf, sizeof(buf))) << strerror(errno); >+ EXPECT_EQ(0, memcmp(buf, CONTENTS0, size0)); >+ >+ /* Evict the data cache */ >+ iia.mock = m_mock; >+ iia.ino = ino; >+ iia.off = 0; >+ iia.len = 0; >+ ASSERT_EQ(0, pthread_create(&th0, NULL, inval_inode, &iia)) >+ << strerror(errno); >+ pthread_join(th0, &thr0_value); >+ EXPECT_EQ(0, (intptr_t)thr0_value); >+ >+ /* cache attributes were purged; this will trigger a new GETATTR */ > EXPECT_CALL(*m_mock, process( > ResultOf([=](auto in) { > return (in.header.opcode == FUSE_GETATTR && >@@ -356,13 +376,45 @@ > out.body.attr.attr.size = size1; > out.body.attr.attr.uid = uid; > }))); >- expect_read(ino, 0, size0, size0, CONTENTS0); > expect_read(ino, 0, size1, size1, CONTENTS1); >+ ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); >+ EXPECT_EQ(uid, sb.st_uid); >+ EXPECT_EQ(size1, sb.st_size); > >+ /* This read should not be serviced by cache */ >+ ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); >+ ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); >+ EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); >+ >+ leak(fd); >+} >+ >+TEST_F(Notify, inval_inode_with_clean_cache) >+{ >+ const static char FULLPATH[] = "mountpoint/foo"; >+ const static char RELPATH[] = "foo"; >+ const char CONTENTS0[] = "abcdefgh"; >+ const char CONTENTS1[] = "ijklmnopqrstuvwxyz"; >+ struct inval_inode_args iia; >+ struct stat sb; >+ ino_t ino = 42; >+ void *thr0_value; >+ Sequence seq; >+ uid_t uid = 12345; >+ pthread_t th0; >+ ssize_t size0 = sizeof(CONTENTS0); >+ ssize_t size1 = sizeof(CONTENTS1); >+ char buf[80]; >+ int fd; >+ >+ expect_lookup(FUSE_ROOT_ID, RELPATH, ino, size0, seq); >+ expect_open(ino, 0, 1); >+ expect_read(ino, 0, size0, size0, CONTENTS0); >+ > /* Fill the data cache */ > fd = open(FULLPATH, O_RDWR); > ASSERT_LE(0, fd) << strerror(errno); >- ASSERT_EQ(size0, read(fd, buf, size0)) << strerror(errno); >+ ASSERT_EQ(size0, read(fd, buf, sizeof(buf))) << strerror(errno); > EXPECT_EQ(0, memcmp(buf, CONTENTS0, size0)); > > /* Evict the data cache */ >@@ -376,6 +428,20 @@ > EXPECT_EQ(0, (intptr_t)thr0_value); > > /* cache attributes were purged; this will trigger a new GETATTR */ >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_GETATTR && >+ in.header.nodeid == ino); >+ }, Eq(true)), >+ _) >+ ).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { >+ SET_OUT_HEADER_LEN(out, attr); >+ out.body.attr.attr.mode = S_IFREG | 0644; >+ out.body.attr.attr_valid = UINT64_MAX; >+ out.body.attr.attr.size = size1; >+ out.body.attr.attr.uid = uid; >+ }))); >+ expect_read(ino, 0, size1, size1, CONTENTS1); > ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); > EXPECT_EQ(uid, sb.st_uid); > EXPECT_EQ(size1, sb.st_size); >@@ -382,7 +448,7 @@ > > /* This read should not be serviced by cache */ > ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); >- ASSERT_EQ(size1, read(fd, buf, size1)) << strerror(errno); >+ ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); > EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); > > leak(fd); >@@ -441,7 +507,7 @@ > EXPECT_EQ(0, (intptr_t)thr0_value); > > /* This read should be serviced by cache */ >- ASSERT_EQ(size1, read(fd, buf, size1)) << strerror(errno); >+ ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); > EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); > > leak(fd); >@@ -451,13 +517,16 @@ > { > const static char FULLPATH[] = "mountpoint/foo"; > const static char RELPATH[] = "foo"; >- const char CONTENTS[] = "abcdefgh"; >+ const char CONTENTS0[] = "abcdefgh"; >+ const char CONTENTS1[] = "ijklmnop"; > struct inval_inode_args iia; > ino_t ino = 42; > void *thr0_value; > Sequence seq; > pthread_t th0; >- ssize_t bufsize = sizeof(CONTENTS); >+ ssize_t size0 = sizeof(CONTENTS0); >+ ssize_t size1 = sizeof(CONTENTS1); >+ char buf[80]; > int fd; > > expect_lookup(FUSE_ROOT_ID, RELPATH, ino, 0, seq); >@@ -466,9 +535,9 @@ > /* Fill the data cache */ > fd = open(FULLPATH, O_RDWR); > ASSERT_LE(0, fd); >- ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); >+ ASSERT_EQ(size0, write(fd, CONTENTS0, size0)) << strerror(errno); > >- expect_write(ino, 0, bufsize, CONTENTS); >+ expect_write(ino, 0, size0, CONTENTS0); > /* > * The FUSE protocol does not require an fsync here, but FreeBSD's > * bufobj_invalbuf sends it anyway >@@ -485,6 +554,26 @@ > pthread_join(th0, &thr0_value); > EXPECT_EQ(0, (intptr_t)thr0_value); > >+ /* >+ * Reading again should trigger another FUSE_READ because the cache >+ * is empty. >+ */ >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_GETATTR && >+ in.header.nodeid == ino); >+ }, Eq(true)), >+ _) >+ ).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { >+ SET_OUT_HEADER_LEN(out, attr); >+ out.body.attr.attr.mode = S_IFREG | 0644; >+ out.body.attr.attr_valid = UINT64_MAX; >+ out.body.attr.attr.size = size1; >+ }))); >+ expect_read(ino, 0, size1, size1, CONTENTS1); >+ ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); >+ ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); >+ > leak(fd); > } > >Index: tests/sys/fs/fusefs/read.cc >=================================================================== >--- tests/sys/fs/fusefs/read.cc (revision 360614) >+++ tests/sys/fs/fusefs/read.cc (working copy) >@@ -828,7 +828,7 @@ > > /* sendfile should fail gracefully if fuse declines the read */ > /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236466 */ >-TEST_F(Read, sendfile_eio) >+TEST_F(Read, DISABLED_sendfile_eio) > { > const char FULLPATH[] = "mountpoint/some_file.txt"; > const char RELPATH[] = "some_file.txt"; >Index: tests/sys/fs/fusefs/rename.cc >=================================================================== >--- tests/sys/fs/fusefs/rename.cc (revision 360614) >+++ tests/sys/fs/fusefs/rename.cc (working copy) >@@ -53,24 +53,6 @@ > > FuseTest::TearDown(); > } >- >- void expect_getattr(uint64_t ino, mode_t mode) >- { >- EXPECT_CALL(*m_mock, process( >- ResultOf([=](auto in) { >- return (in.header.opcode == FUSE_GETATTR && >- in.header.nodeid == ino); >- }, Eq(true)), >- _) >- ).WillOnce(Invoke( >- ReturnImmediate([=](auto i __unused, auto& out) { >- SET_OUT_HEADER_LEN(out, attr); >- out.body.attr.attr.ino = ino; // Must match nodeid >- out.body.attr.attr.mode = mode; >- out.body.attr.attr_valid = UINT64_MAX; >- }))); >- } >- > }; > > // EINVAL, dst is subdir of src >@@ -82,7 +64,6 @@ > const char RELSRC[] = "src"; > uint64_t src_ino = 42; > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELSRC, src_ino, S_IFDIR | 0755, 0, 2); > EXPECT_LOOKUP(src_ino, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT))); > >@@ -123,7 +104,6 @@ > */ > struct timespec entry_valid = {.tv_sec = 0, .tv_nsec = 0}; > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); > /* LOOKUP returns a negative cache entry for dst */ > EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) >@@ -158,7 +138,6 @@ > uint64_t ino = 42; > struct timespec entry_valid = {.tv_sec = TIME_T_MAX, .tv_nsec = 0}; > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); > /* LOOKUP returns a negative cache entry for dst */ > EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) >@@ -196,7 +175,6 @@ > tmpfd = mkstemp(tmpfile); > ASSERT_LE(0, tmpfd) << strerror(errno); > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELB, b_ino, S_IFREG | 0644, 0, 2); > > ASSERT_NE(0, rename(tmpfile, FULLB)); >@@ -215,7 +193,6 @@ > uint64_t dst_dir_ino = FUSE_ROOT_ID; > uint64_t ino = 42; > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); > EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) > .WillOnce(Invoke(ReturnErrno(ENOENT))); >@@ -251,7 +228,6 @@ > struct stat sb; > > expect_lookup(RELSRC, ino, S_IFDIR | 0755, 0, 1); >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > EXPECT_LOOKUP(FUSE_ROOT_ID, RELDSTDIR) > .WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { > SET_OUT_HEADER_LEN(out, entry); >@@ -303,7 +279,6 @@ > uint64_t dst_dir_ino = FUSE_ROOT_ID; > uint64_t ino = 42; > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); > expect_lookup(RELDST, dst_ino, S_IFREG | 0644, 0, 1); > EXPECT_CALL(*m_mock, process( >Index: tests/sys/fs/fusefs/rmdir.cc >=================================================================== >--- tests/sys/fs/fusefs/rmdir.cc (revision 360614) >+++ tests/sys/fs/fusefs/rmdir.cc (working copy) >@@ -42,22 +42,6 @@ > > class Rmdir: public FuseTest { > public: >-void expect_getattr(uint64_t ino, mode_t mode) >-{ >- EXPECT_CALL(*m_mock, process( >- ResultOf([=](auto in) { >- return (in.header.opcode == FUSE_GETATTR && >- in.header.nodeid == ino); >- }, Eq(true)), >- _) >- ).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { >- SET_OUT_HEADER_LEN(out, attr); >- out.body.attr.attr.ino = ino; // Must match nodeid >- out.body.attr.attr.mode = mode; >- out.body.attr.attr_valid = UINT64_MAX; >- }))); >-} >- > void expect_lookup(const char *relpath, uint64_t ino, int times=1) > { > EXPECT_LOOKUP(FUSE_ROOT_ID, relpath) >@@ -95,25 +79,34 @@ > struct stat sb; > sem_t sem; > uint64_t ino = 42; >+ Sequence seq; > > ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno); > >+ expect_lookup(RELPATH, ino); > EXPECT_CALL(*m_mock, process( > ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_RMDIR && >+ 0 == strcmp(RELPATH, in.body.rmdir) && >+ in.header.nodeid == FUSE_ROOT_ID); >+ }, Eq(true)), >+ _) >+ ).InSequence(seq) >+ .WillOnce(Invoke(ReturnErrno(0))); >+ expect_forget(ino, 1, &sem); >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { > return (in.header.opcode == FUSE_GETATTR && > in.header.nodeid == FUSE_ROOT_ID); > }, Eq(true)), > _) >- ).Times(2) >+ ).InSequence(seq) > .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { > SET_OUT_HEADER_LEN(out, attr); >- out.body.attr.attr.ino = ino; // Must match nodeid >+ out.body.attr.attr.ino = FUSE_ROOT_ID; > out.body.attr.attr.mode = S_IFDIR | 0755; > out.body.attr.attr_valid = UINT64_MAX; > }))); >- expect_lookup(RELPATH, ino); >- expect_rmdir(FUSE_ROOT_ID, RELPATH, 0); >- expect_forget(ino, 1, &sem); > > ASSERT_EQ(0, rmdir(FULLPATH)) << strerror(errno); > EXPECT_EQ(0, stat("mountpoint", &sb)) << strerror(errno); >@@ -127,7 +120,6 @@ > const char RELPATH[] = "some_dir"; > uint64_t ino = 42; > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELPATH, ino); > expect_rmdir(FUSE_ROOT_ID, RELPATH, ENOTEMPTY); > >@@ -143,7 +135,6 @@ > sem_t sem; > uint64_t ino = 42; > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH, ino, 2); > expect_rmdir(FUSE_ROOT_ID, RELPATH, 0); > expect_forget(ino, 1, &sem); >@@ -163,7 +154,6 @@ > > ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno); > >- expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); > expect_lookup(RELPATH, ino); > expect_rmdir(FUSE_ROOT_ID, RELPATH, 0); > expect_forget(ino, 1, &sem); >Index: tests/sys/fs/fusefs/unlink.cc >=================================================================== >--- tests/sys/fs/fusefs/unlink.cc (revision 360614) >+++ tests/sys/fs/fusefs/unlink.cc (working copy) >@@ -41,22 +41,6 @@ > > class Unlink: public FuseTest { > public: >-void expect_getattr(uint64_t ino, mode_t mode) >-{ >- EXPECT_CALL(*m_mock, process( >- ResultOf([=](auto in) { >- return (in.header.opcode == FUSE_GETATTR && >- in.header.nodeid == ino); >- }, Eq(true)), >- _) >- ).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { >- SET_OUT_HEADER_LEN(out, attr); >- out.body.attr.attr.ino = ino; // Must match nodeid >- out.body.attr.attr.mode = mode; >- out.body.attr.attr_valid = UINT64_MAX; >- }))); >-} >- > void expect_lookup(const char *relpath, uint64_t ino, int times, int nlink=1) > { > EXPECT_LOOKUP(FUSE_ROOT_ID, relpath) >@@ -89,7 +73,6 @@ > struct stat sb_old, sb_new; > int fd1; > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH0, ino, 1, 2); > expect_lookup(RELPATH1, ino, 1, 2); > expect_open(ino, 0, 1); >@@ -117,23 +100,32 @@ > const char RELPATH[] = "some_file.txt"; > struct stat sb; > uint64_t ino = 42; >+ Sequence seq; > >+ /* Use nlink=2 so we don't get a FUSE_FORGET */ >+ expect_lookup(RELPATH, ino, 1, 2); > EXPECT_CALL(*m_mock, process( > ResultOf([=](auto in) { >+ return (in.header.opcode == FUSE_UNLINK && >+ 0 == strcmp(RELPATH, in.body.unlink) && >+ in.header.nodeid == FUSE_ROOT_ID); >+ }, Eq(true)), >+ _) >+ ).InSequence(seq) >+ .WillOnce(Invoke(ReturnErrno(0))); >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { > return (in.header.opcode == FUSE_GETATTR && > in.header.nodeid == FUSE_ROOT_ID); > }, Eq(true)), > _) >- ).Times(2) >+ ).InSequence(seq) > .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { > SET_OUT_HEADER_LEN(out, attr); >- out.body.attr.attr.ino = ino; // Must match nodeid >+ out.body.attr.attr.ino = FUSE_ROOT_ID; > out.body.attr.attr.mode = S_IFDIR | 0755; > out.body.attr.attr_valid = UINT64_MAX; > }))); >- /* Use nlink=2 so we don't get a FUSE_FORGET */ >- expect_lookup(RELPATH, ino, 1, 2); >- expect_unlink(1, RELPATH, 0); > > ASSERT_EQ(0, unlink(FULLPATH)) << strerror(errno); > EXPECT_EQ(0, stat("mountpoint", &sb)) << strerror(errno); >@@ -145,7 +137,6 @@ > const char RELPATH[] = "some_file.txt"; > uint64_t ino = 42; > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH, ino, 1); > expect_unlink(1, RELPATH, EPERM); > >@@ -162,7 +153,6 @@ > const char RELPATH[] = "some_file.txt"; > uint64_t ino = 42; > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH, ino, 2, 2); > expect_unlink(1, RELPATH, 0); > >@@ -182,7 +172,6 @@ > const char RELPATH1[] = "other_file.txt"; > uint64_t ino = 42; > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH0, ino, 1, 2); > expect_unlink(1, RELPATH0, 0); > EXPECT_CALL(*m_mock, process( >@@ -213,7 +202,6 @@ > > ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno); > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH, ino, 1); > expect_unlink(1, RELPATH, 0); > expect_forget(ino, 1, &sem); >@@ -233,7 +221,6 @@ > uint64_t ino = 42; > int fd; > >- expect_getattr(1, S_IFDIR | 0755); > expect_lookup(RELPATH0, ino, 2); > expect_open(ino, 0, 1); > expect_unlink(1, RELPATH0, 0); >Index: tests/sys/fs/fusefs/utils.cc >=================================================================== >--- tests/sys/fs/fusefs/utils.cc (revision 360614) >+++ tests/sys/fs/fusefs/utils.cc (working copy) >@@ -273,6 +273,20 @@ > }))); > } > >+void FuseTest::expect_getxattr(uint64_t ino, const char *attr, ProcessMockerT r) >+{ >+ EXPECT_CALL(*m_mock, process( >+ ResultOf([=](auto in) { >+ const char *a = (const char*)in.body.bytes + >+ sizeof(fuse_getxattr_in); >+ return (in.header.opcode == FUSE_GETXATTR && >+ in.header.nodeid == ino && >+ 0 == strcmp(attr, a)); >+ }, Eq(true)), >+ _) >+ ).WillOnce(Invoke(r)); >+} >+ > void FuseTest::expect_lookup(const char *relpath, uint64_t ino, mode_t mode, > uint64_t size, int times, uint64_t attr_valid, uid_t uid, gid_t gid) > { >Index: tests/sys/fs/fusefs/utils.hh >=================================================================== >--- tests/sys/fs/fusefs/utils.hh (revision 360614) >+++ tests/sys/fs/fusefs/utils.hh (working copy) >@@ -133,6 +133,12 @@ > void expect_getattr(uint64_t ino, uint64_t size); > > /* >+ * Create an expectation that FUSE_GETXATTR will be called once for the >+ * given inode. >+ */ >+ void expect_getxattr(uint64_t ino, const char *attr, ProcessMockerT r); >+ >+ /* > * Create an expectation that FUSE_LOOKUP will be called for the given > * path exactly times times and cache validity period. It will respond > * with inode ino, mode mode, filesize size. >Index: tests/sys/fs/fusefs/xattr.cc >=================================================================== >--- tests/sys/fs/fusefs/xattr.cc (revision 360614) >+++ tests/sys/fs/fusefs/xattr.cc (working copy) >@@ -62,20 +62,6 @@ > > class Xattr: public FuseTest { > public: >-void expect_getxattr(uint64_t ino, const char *attr, ProcessMockerT r) >-{ >- EXPECT_CALL(*m_mock, process( >- ResultOf([=](auto in) { >- const char *a = (const char*)in.body.bytes + >- sizeof(fuse_getxattr_in); >- return (in.header.opcode == FUSE_GETXATTR && >- in.header.nodeid == ino && >- 0 == strcmp(attr, a)); >- }, Eq(true)), >- _) >- ).WillOnce(Invoke(r)); >-} >- > void expect_listxattr(uint64_t ino, uint32_t size, ProcessMockerT r, > Sequence *seq = NULL) > {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 245689
:
213598
| 214294