From owner-svn-src-projects@freebsd.org Fri Jun 28 18:48:03 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 35BF515C8E25 for ; Fri, 28 Jun 2019 18:48:03 +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 CD1CB842B5; Fri, 28 Jun 2019 18:48:02 +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 A77702CC9; Fri, 28 Jun 2019 18:48:02 +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 x5SIm2sv043792; Fri, 28 Jun 2019 18:48:02 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x5SIm2Mo043791; Fri, 28 Jun 2019 18:48:02 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201906281848.x5SIm2Mo043791@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Fri, 28 Jun 2019 18:48:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r349513 - 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: 349513 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: CD1CB842B5 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.98 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.98)[-0.981,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: Fri, 28 Jun 2019 18:48:03 -0000 Author: asomers Date: Fri Jun 28 18:48:02 2019 New Revision: 349513 URL: https://svnweb.freebsd.org/changeset/base/349513 Log: fusefs: don't leak memory of unsent operations on unmount Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_device.c projects/fuse2/tests/sys/fs/fusefs/destroy.cc Modified: projects/fuse2/sys/fs/fuse/fuse_device.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_device.c Fri Jun 28 18:03:13 2019 (r349512) +++ projects/fuse2/sys/fs/fuse/fuse_device.c Fri Jun 28 18:48:02 2019 (r349513) @@ -157,6 +157,13 @@ fdata_dtor(void *arg) fuse_ticket_drop(tick); } fuse_lck_mtx_unlock(fdata->aw_mtx); + + /* Cleanup unsent operations */ + fuse_lck_mtx_lock(fdata->ms_mtx); + while ((tick = fuse_ms_pop(fdata))) { + fuse_ticket_drop(tick); + } + fuse_lck_mtx_unlock(fdata->ms_mtx); FUSE_UNLOCK(); fdata_trydestroy(fdata); Modified: projects/fuse2/tests/sys/fs/fusefs/destroy.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/destroy.cc Fri Jun 28 18:03:13 2019 (r349512) +++ projects/fuse2/tests/sys/fs/fusefs/destroy.cc Fri Jun 28 18:48:02 2019 (r349513) @@ -28,12 +28,105 @@ * SUCH DAMAGE. */ +extern "C" { +#include +#include +#include +} + #include "mockfs.hh" #include "utils.hh" using namespace testing; +/* Tests for orderly unmounts */ class Destroy: public FuseTest {}; + +/* Tests for unexpected deaths of the server */ +class Death: public FuseTest{}; + +static void* open_th(void* arg) { + int fd; + const char *path = (const char*)arg; + + fd = open(path, O_RDONLY); + EXPECT_EQ(-1, fd); + EXPECT_EQ(ENOTCONN, errno); + return 0; +} + +/* + * The server dies with unsent operations still on the message queue. + * Check for any memory leaks like this: + * 1) kldunload fusefs, if necessary + * 2) kldload fusefs + * 3) ./destroy --gtest_filter=Destroy.unsent_operations + * 4) kldunload fusefs + * 5) check /var/log/messages for anything like this: +Freed UMA keg (fuse_ticket) was not empty (31 items). Lost 2 pages of memory. +Warning: memory type fuse_msgbuf leaked memory on destroy (68 allocations, 428800 bytes leaked). + */ +TEST_F(Death, unsent_operations) +{ + const char FULLPATH0[] = "mountpoint/some_file.txt"; + const char FULLPATH1[] = "mountpoint/other_file.txt"; + const char RELPATH0[] = "some_file.txt"; + const char RELPATH1[] = "other_file.txt"; + pthread_t th0, th1; + ino_t ino0 = 42, ino1 = 43; + sem_t sem; + mode_t mode = S_IFREG | 0644; + + sem_init(&sem, 0, 0); + + EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH0) + .WillRepeatedly(Invoke( + ReturnImmediate([=](auto in __unused, auto& out) { + SET_OUT_HEADER_LEN(out, entry); + out.body.entry.attr.mode = mode; + out.body.entry.nodeid = ino0; + out.body.entry.attr.nlink = 1; + }))); + EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH1) + .WillRepeatedly(Invoke( + ReturnImmediate([=](auto in __unused, auto& out) { + SET_OUT_HEADER_LEN(out, entry); + out.body.entry.attr.mode = mode; + out.body.entry.nodeid = ino1; + out.body.entry.attr.nlink = 1; + }))); + + EXPECT_CALL(*m_mock, process( + ResultOf([&](auto in) { + return (in.header.opcode == FUSE_OPEN); + }, Eq(true)), + _) + ).WillOnce(Invoke([&](auto in __unused, auto &out __unused) { + sem_post(&sem); + pause(); + })); + + /* + * One thread's operation will be sent to the daemon and block, and the + * other's will be stuck in the message queue. + */ + ASSERT_EQ(0, pthread_create(&th0, NULL, open_th, (void*)FULLPATH0)) + << strerror(errno); + ASSERT_EQ(0, pthread_create(&th1, NULL, open_th, (void*)FULLPATH1)) + << strerror(errno); + + /* Wait for the first thread to block */ + sem_wait(&sem); + /* Give the second thread time to block */ + nap(); + + m_mock->kill_daemon(); + + pthread_join(th0, NULL); + pthread_join(th1, NULL); + + sem_destroy(&sem); +} /* * On unmount the kernel should send a FUSE_DESTROY operation. It should also