From owner-svn-src-projects@freebsd.org Tue Sep 3 14:07:28 2019 Return-Path: Delivered-To: svn-src-projects@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 18BCEDDB25 for ; Tue, 3 Sep 2019 14:07:27 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) (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 "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46N80Z3D0kz4QcF; Tue, 3 Sep 2019 14:07:26 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 1452) id 3278E1B64F; Tue, 3 Sep 2019 14:06:40 +0000 (UTC) X-Original-To: yuripv@localmail.freebsd.org Delivered-To: yuripv@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 651B518CB8; Wed, 24 Apr 2019 14:25:39 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [96.47.72.132]) (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 "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 26B5F8F10D; Wed, 24 Apr 2019 14:25:39 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 538) id 0EBFD18CB6; Wed, 24 Apr 2019 14:25:39 +0000 (UTC) Delivered-To: src-committers@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 1A2CC18CB4 for ; Wed, 24 Apr 2019 14:25:36 +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 CCEEC8F10B; Wed, 24 Apr 2019 14:25:35 +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 84637D75E; Wed, 24 Apr 2019 14:25:35 +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 x3OEPZUK075538; Wed, 24 Apr 2019 14:25:35 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3OEPZeE075537; Wed, 24 Apr 2019 14:25:35 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904241425.x3OEPZeE075537@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346637 - projects/fuse2/tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: projects/fuse2/tests/sys/fs/fusefs X-SVN-Commit-Revision: 346637 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk X-Loop: FreeBSD.org Sender: owner-src-committers@freebsd.org X-Rspamd-Queue-Id: 26B5F8F10D X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[freebsd.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.96)[-0.962,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; ASN(0.00)[asn:11403, ipnet:96.47.64.0/20, country:US] Status: O X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Date: Tue, 03 Sep 2019 14:07:28 -0000 X-Original-Date: Wed, 24 Apr 2019 14:25:35 +0000 (UTC) X-List-Received-Date: Tue, 03 Sep 2019 14:07:28 -0000 Author: asomers Date: Wed Apr 24 14:25:35 2019 New Revision: 346637 URL: https://svnweb.freebsd.org/changeset/base/346637 Log: fusefs: fix the FUSE_INTERRUPT tests when data_cache_mode==2 Replace most write operations with mkdir so they won't be affected by the setting of vfs.fusefs.data_cache_mode. Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Wed Apr 24 14:08:16 2019 (r346636) +++ projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Wed Apr 24 14:25:35 2019 (r346637) @@ -45,6 +45,10 @@ using namespace testing; /* Initial size of files used by these tests */ const off_t FILESIZE = 1000; +/* Access mode used by all directories in these tests */ +const mode_t MODE = 0755; +const char FULLDIRPATH0[] = "mountpoint/some_dir"; +const char RELDIRPATH0[] = "some_dir"; static sem_t *signaled_semaphore; @@ -83,6 +87,23 @@ void expect_lookup(const char *relpath, uint64_t ino) } /* + * Expect a FUSE_MKDIR but don't reply. Instead, just record the unique value + * to the provided pointer + */ +void expect_mkdir(uint64_t *mkdir_unique) +{ + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_MKDIR); + + }, Eq(true)), + _) + ).WillOnce(Invoke([=](auto in, auto &out __unused) { + *mkdir_unique = in->header.unique; + })); +} + +/* * Expect a FUSE_READ but don't reply. Instead, just record the unique value * to the provided pointer */ @@ -149,32 +170,27 @@ void TearDown() { /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ TEST_F(Interrupt, already_complete) { - const char FULLPATH[] = "mountpoint/some_file.txt"; - const char RELPATH[] = "some_file.txt"; - const char *CONTENTS = "abcdefgh"; uint64_t ino = 42; - int fd; - ssize_t bufsize = strlen(CONTENTS); pthread_t self; - uint64_t write_unique = 0; + uint64_t mkdir_unique = 0; self = pthread_self(); - expect_lookup(RELPATH, ino); - expect_open(ino, 0, 1); - expect_write(ino, &write_unique); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); + expect_mkdir(&mkdir_unique); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).WillOnce(Invoke([&](auto in, auto &out) { - // First complete the write request + // First complete the mkdir request auto out0 = new mockfs_buf_out; - out0->header.unique = write_unique; - SET_OUT_HEADER_LEN(out0, write); - out0->body.write.size = bufsize; + out0->header.unique = mkdir_unique; + SET_OUT_HEADER_LEN(out0, entry); + out0->body.create.entry.attr.mode = S_IFDIR | MODE; + out0->body.create.entry.nodeid = ino; out.push_back(out0); // Then, respond EAGAIN to the interrupt request @@ -185,13 +201,8 @@ TEST_F(Interrupt, already_complete) out.push_back(out1); })); - fd = open(FULLPATH, O_WRONLY); - ASSERT_LE(0, fd) << strerror(errno); - setup_interruptor(self); - EXPECT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); - - /* Deliberately leak fd. close(2) will be tested in release.cc */ + EXPECT_EQ(0, mkdir(FULLDIRPATH0, MODE)) << strerror(errno); } /* @@ -200,45 +211,31 @@ TEST_F(Interrupt, already_complete) */ TEST_F(Interrupt, fatal_signal) { - const char FULLPATH[] = "mountpoint/some_file.txt"; - const char *CONTENTS = "abcdefgh"; - const char RELPATH[] = "some_file.txt"; - ssize_t bufsize = strlen(CONTENTS); - uint64_t ino = 42; int status; pthread_t self; - uint64_t write_unique; + uint64_t mkdir_unique; self = pthread_self(); - expect_lookup(RELPATH, ino); - expect_open(ino, 0, 1); - expect_write(ino, &write_unique); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); + expect_mkdir(&mkdir_unique); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).WillOnce(Invoke([&](auto in __unused, auto &out __unused) { /* Don't respond. The process should exit anyway */ })); - expect_flush(ino, 1, ReturnErrno(0)); - expect_release(ino, FH); fork(false, &status, [&] { }, [&]() { struct sigaction sa; - int fd, r; + int r; pthread_t killer_th; pthread_t self; - fd = open(FULLPATH, O_WRONLY); - if (fd < 0) { - perror("open"); - return 1; - } - /* SIGUSR2 terminates the process by default */ bzero(&sa, sizeof(sa)); sa.sa_handler = SIG_DFL; @@ -254,12 +251,10 @@ TEST_F(Interrupt, fatal_signal) return 1; } - write(fd, CONTENTS, bufsize); + mkdir(FULLDIRPATH0, MODE); return 1; }); ASSERT_EQ(SIGUSR2, WTERMSIG(status)); - - /* Deliberately leak fd. close(2) will be tested in release.cc */ } /* @@ -269,45 +264,45 @@ TEST_F(Interrupt, fatal_signal) /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ TEST_F(Interrupt, ignore) { - const char FULLPATH[] = "mountpoint/some_file.txt"; - const char RELPATH[] = "some_file.txt"; - const char *CONTENTS = "abcdefgh"; uint64_t ino = 42; - int fd; - ssize_t bufsize = strlen(CONTENTS); pthread_t self; - uint64_t write_unique; + uint64_t mkdir_unique; self = pthread_self(); - expect_lookup(RELPATH, ino); - expect_open(ino, 0, 1); - expect_write(ino, &write_unique); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); + expect_mkdir(&mkdir_unique); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).WillOnce(Invoke([&](auto in __unused, auto &out) { // Ignore FUSE_INTERRUPT; respond to the FUSE_WRITE auto out0 = new mockfs_buf_out; - out0->header.unique = write_unique; - SET_OUT_HEADER_LEN(out0, write); - out0->body.write.size = bufsize; + out0->header.unique = mkdir_unique; + SET_OUT_HEADER_LEN(out0, entry); + out0->body.create.entry.attr.mode = S_IFDIR | MODE; + out0->body.create.entry.nodeid = ino; out.push_back(out0); })); - fd = open(FULLPATH, O_WRONLY); - ASSERT_LE(0, fd) << strerror(errno); - setup_interruptor(self); - ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); + ASSERT_EQ(0, mkdir(FULLDIRPATH0, MODE)) << strerror(errno); +} - /* Deliberately leak fd. close(2) will be tested in release.cc */ +void* mkdir0(void* arg __unused) { + ssize_t r; + + r = mkdir(FULLDIRPATH0, MODE); + if (r >= 0) + return 0; + else + return (void*)(intptr_t)errno; } -void* write0(void* arg) { +void* setxattr0(void* arg) { const char *CONTENTS = "abcdefgh"; ssize_t bufsize = strlen(CONTENTS); int fd = (int)(intptr_t)arg; @@ -334,87 +329,16 @@ void* read1(void* arg) { } /* - * An operation that hasn't yet been sent to userland can be interrupted - * without sending FUSE_INTERRUPT - */ -TEST_F(Interrupt, in_kernel) -{ - 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"; - const char *CONTENTS = "ijklmnop"; - ssize_t bufsize = strlen(CONTENTS); - uint64_t ino0 = 42, ino1 = 43; - int fd0, fd1; - pthread_t self, th0; - sem_t sem0, sem1; - void *thr0_value; - - ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno); - ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); - self = pthread_self(); - - expect_lookup(RELPATH0, ino0); - expect_open(ino0, 0, 1); - expect_lookup(RELPATH1, ino1); - expect_open(ino1, 0, 1); - EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { - return (in->header.opcode == FUSE_WRITE && - in->header.nodeid == ino0); - }, Eq(true)), - _) - ).WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { - /* Let the next write proceed */ - sem_post(&sem1); - /* Pause the daemon thread so it won't read the next op */ - sem_wait(&sem0); - - SET_OUT_HEADER_LEN(out, write); - out->body.write.size = in->body.write.size; - }))); - - fd0 = open(FULLPATH0, O_WRONLY); - ASSERT_LE(0, fd0) << strerror(errno); - fd1 = open(FULLPATH1, O_WRONLY); - ASSERT_LE(0, fd1) << strerror(errno); - - /* Use a separate thread for the first write */ - ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) - << strerror(errno); - - setup_interruptor(self); - - sem_wait(&sem1); /* Sequence the two writes */ - ASSERT_EQ(-1, write(fd1, CONTENTS, bufsize)); - EXPECT_EQ(EINTR, errno); - - /* Unstick the daemon */ - ASSERT_EQ(0, sem_post(&sem0)) << strerror(errno); - - /* Wait awhile to make sure the signal generates no FUSE_INTERRUPT */ - usleep(250'000); - - pthread_join(th0, &thr0_value); - EXPECT_EQ(0, (intptr_t)thr0_value); - sem_destroy(&sem1); - sem_destroy(&sem0); -} - -/* * A restartable operation (basically, anything except write or setextattr) * that hasn't yet been sent to userland can be interrupted without sending * FUSE_INTERRUPT, and will be automatically restarted. */ TEST_F(Interrupt, in_kernel_restartable) { - 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"; uint64_t ino0 = 42, ino1 = 43; - int fd0, fd1; + int fd1; pthread_t self, th0, th1; sem_t sem0, sem1; void *thr0_value, *thr1_value; @@ -423,34 +347,31 @@ TEST_F(Interrupt, in_kernel_restartable) ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); self = pthread_self(); - expect_lookup(RELPATH0, ino0); - expect_open(ino0, 0, 1); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); expect_lookup(RELPATH1, ino1); expect_open(ino1, 0, 1); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { - return (in->header.opcode == FUSE_WRITE && - in->header.nodeid == ino0); + return (in->header.opcode == FUSE_MKDIR); }, Eq(true)), _) - ).WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { + ).WillOnce(Invoke(ReturnImmediate([&](auto in __unused, auto out) { /* Let the next write proceed */ sem_post(&sem1); /* Pause the daemon thread so it won't read the next op */ sem_wait(&sem0); - SET_OUT_HEADER_LEN(out, write); - out->body.write.size = in->body.write.size; + SET_OUT_HEADER_LEN(out, entry); + out->body.create.entry.attr.mode = S_IFDIR | MODE; + out->body.create.entry.nodeid = ino0; }))); FuseTest::expect_read(ino1, 0, FILESIZE, 0, NULL); - fd0 = open(FULLPATH0, O_WRONLY); - ASSERT_LE(0, fd0) << strerror(errno); fd1 = open(FULLPATH1, O_RDONLY); ASSERT_LE(0, fd1) << strerror(errno); /* Use a separate thread for each operation */ - ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + ASSERT_EQ(0, pthread_create(&th0, NULL, mkdir0, NULL)) << strerror(errno); sem_wait(&sem1); /* Sequence the two operations */ @@ -476,21 +397,20 @@ TEST_F(Interrupt, in_kernel_restartable) sem_destroy(&sem0); } -/* - * Like FUSE_WRITE, FUSE_SETXATTR is non-restartable because it calls uiomove - * before blocking in fticket_wait_answ +/* + * An operation that hasn't yet been sent to userland can be interrupted + * without sending FUSE_INTERRUPT. If it's a non-restartable operation (write + * or setextattr) it will return EINTR. */ -TEST_F(Interrupt, in_kernel_setxattr) +TEST_F(Interrupt, in_kernel_nonrestartable) { - 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"; const char value[] = "whatever"; ssize_t value_len = strlen(value) + 1; uint64_t ino0 = 42, ino1 = 43; int ns = EXTATTR_NAMESPACE_USER; - int fd0, fd1; + int fd1; pthread_t self, th0; sem_t sem0, sem1; void *thr0_value; @@ -500,33 +420,30 @@ TEST_F(Interrupt, in_kernel_setxattr) ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); self = pthread_self(); - expect_lookup(RELPATH0, ino0); - expect_open(ino0, 0, 1); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); expect_lookup(RELPATH1, ino1); expect_open(ino1, 0, 1); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { - return (in->header.opcode == FUSE_WRITE && - in->header.nodeid == ino0); + return (in->header.opcode == FUSE_MKDIR); }, Eq(true)), _) - ).WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { + ).WillOnce(Invoke(ReturnImmediate([&](auto in __unused, auto out) { /* Let the next write proceed */ sem_post(&sem1); /* Pause the daemon thread so it won't read the next op */ sem_wait(&sem0); - SET_OUT_HEADER_LEN(out, write); - out->body.write.size = in->body.write.size; + SET_OUT_HEADER_LEN(out, entry); + out->body.create.entry.attr.mode = S_IFDIR | MODE; + out->body.create.entry.nodeid = ino0; }))); - fd0 = open(FULLPATH0, O_WRONLY); - ASSERT_LE(0, fd0) << strerror(errno); fd1 = open(FULLPATH1, O_WRONLY); ASSERT_LE(0, fd1) << strerror(errno); /* Use a separate thread for the first write */ - ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + ASSERT_EQ(0, pthread_create(&th0, NULL, mkdir0, NULL)) << strerror(errno); setup_interruptor(self); @@ -556,42 +473,30 @@ TEST_F(Interrupt, in_kernel_setxattr) /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ TEST_F(Interrupt, in_progress) { - const char FULLPATH[] = "mountpoint/some_file.txt"; - const char RELPATH[] = "some_file.txt"; - const char *CONTENTS = "abcdefgh"; - uint64_t ino = 42; - int fd; - ssize_t bufsize = strlen(CONTENTS); pthread_t self; - uint64_t write_unique; + uint64_t mkdir_unique; self = pthread_self(); - expect_lookup(RELPATH, ino); - expect_open(ino, 0, 1); - expect_write(ino, &write_unique); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); + expect_mkdir(&mkdir_unique); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).WillOnce(Invoke([&](auto in __unused, auto &out) { auto out0 = new mockfs_buf_out; out0->header.error = -EINTR; - out0->header.unique = write_unique; + out0->header.unique = mkdir_unique; out0->header.len = sizeof(out0->header); out.push_back(out0); })); - fd = open(FULLPATH, O_WRONLY); - ASSERT_LE(0, fd) << strerror(errno); - setup_interruptor(self); - ASSERT_EQ(-1, write(fd, CONTENTS, bufsize)); + ASSERT_EQ(-1, mkdir(FULLDIRPATH0, MODE)); EXPECT_EQ(EINTR, errno); - - /* Deliberately leak fd. close(2) will be tested in release.cc */ } /* Reads should also be interruptible */ @@ -638,16 +543,11 @@ TEST_F(Interrupt, in_progress_read) /* FUSE_INTERRUPT operations should take priority over other pending ops */ TEST_F(Interrupt, priority) { - 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"; - const char *CONTENTS = "ijklmnop"; + const char FULLPATH1[] = "mountpoint/other_dir"; + const char RELPATH1[] = "other_dir"; Sequence seq; - ssize_t bufsize = strlen(CONTENTS); - uint64_t ino0 = 42, ino1 = 43; - int fd0, fd1; - uint64_t write_unique; + uint64_t ino1 = 43; + uint64_t mkdir_unique; pthread_t self, th0; sem_t sem0, sem1; @@ -655,21 +555,19 @@ TEST_F(Interrupt, priority) ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); self = pthread_self(); - expect_lookup(RELPATH0, ino0); - expect_open(ino0, 0, 1); - expect_lookup(RELPATH1, ino1); - expect_open(ino1, 0, 1); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH1).WillOnce(Invoke(ReturnErrno(ENOENT))); + //expect_mkdir(&mkdir_unique); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { - return (in->header.opcode == FUSE_WRITE && - in->header.nodeid == ino0); + return (in->header.opcode == FUSE_MKDIR); }, Eq(true)), _) ).InSequence(seq) .WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { - write_unique = in->header.unique; + mkdir_unique = in->header.unique; - /* Let the next write proceed */ + /* Let the next mkdir proceed */ sem_post(&sem1); /* Pause the daemon thread so it won't read the next op */ @@ -677,47 +575,42 @@ TEST_F(Interrupt, priority) /* Finally, interrupt the original op */ out->header.error = -EINTR; - out->header.unique = write_unique; + out->header.unique = mkdir_unique; out->header.len = sizeof(out->header); }))); /* - * FUSE_INTERRUPT should be received before the second FUSE_WRITE, even + * FUSE_INTERRUPT should be received before the second FUSE_MKDIR, even * though it was generated later */ EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).InSequence(seq) .WillOnce(Invoke(ReturnErrno(EAGAIN))); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { - return (in->header.opcode == FUSE_WRITE && - in->header.nodeid == ino1); + return (in->header.opcode == FUSE_MKDIR); }, Eq(true)), _) ).InSequence(seq) - .WillOnce(Invoke(ReturnImmediate([=](auto in , auto out) { - SET_OUT_HEADER_LEN(out, write); - out->body.write.size = in->body.write.size; + .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) { + SET_OUT_HEADER_LEN(out, entry); + out->body.create.entry.attr.mode = S_IFDIR | MODE; + out->body.create.entry.nodeid = ino1; }))); - fd0 = open(FULLPATH0, O_WRONLY); - ASSERT_LE(0, fd0) << strerror(errno); - fd1 = open(FULLPATH1, O_WRONLY); - ASSERT_LE(0, fd1) << strerror(errno); - - /* Use a separate thread for the first write */ - ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + /* Use a separate thread for the first mkdir */ + ASSERT_EQ(0, pthread_create(&th0, NULL, mkdir0, NULL)) << strerror(errno); signaled_semaphore = &sem0; - sem_wait(&sem1); /* Sequence the two writes */ + sem_wait(&sem1); /* Sequence the two mkdirs */ setup_interruptor(th0); - ASSERT_EQ(bufsize, write(fd1, CONTENTS, bufsize)) << strerror(errno); + ASSERT_EQ(0, mkdir(FULLPATH1, MODE)) << strerror(errno); /* Wait awhile to make sure the signal generates no FUSE_INTERRUPT */ usleep(250'000); @@ -740,26 +633,19 @@ TEST_F(Interrupt, priority) /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ TEST_F(Interrupt, too_soon) { - const char FULLPATH[] = "mountpoint/some_file.txt"; - const char RELPATH[] = "some_file.txt"; - const char *CONTENTS = "abcdefgh"; Sequence seq; - uint64_t ino = 42; - int fd; - ssize_t bufsize = strlen(CONTENTS); pthread_t self; - uint64_t write_unique; + uint64_t mkdir_unique; self = pthread_self(); - expect_lookup(RELPATH, ino); - expect_open(ino, 0, 1); - expect_write(ino, &write_unique); + EXPECT_LOOKUP(1, RELDIRPATH0).WillOnce(Invoke(ReturnErrno(ENOENT))); + expect_mkdir(&mkdir_unique); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).InSequence(seq) @@ -768,23 +654,20 @@ TEST_F(Interrupt, too_soon) EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && - in->body.interrupt.unique == write_unique); + in->body.interrupt.unique == mkdir_unique); }, Eq(true)), _) ).InSequence(seq) .WillOnce(Invoke([&](auto in __unused, auto &out __unused) { auto out0 = new mockfs_buf_out; out0->header.error = -EINTR; - out0->header.unique = write_unique; + out0->header.unique = mkdir_unique; out0->header.len = sizeof(out0->header); out.push_back(out0); })); - fd = open(FULLPATH, O_WRONLY); - ASSERT_LE(0, fd) << strerror(errno); - setup_interruptor(self); - ASSERT_EQ(-1, write(fd, CONTENTS, bufsize)); + ASSERT_EQ(-1, mkdir(FULLDIRPATH0, MODE)); EXPECT_EQ(EINTR, errno); /* Deliberately leak fd. close(2) will be tested in release.cc */