19821f1d3SAlan Somers /*- 29821f1d3SAlan Somers * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 39821f1d3SAlan Somers * 49821f1d3SAlan Somers * Copyright (c) 2019 The FreeBSD Foundation 59821f1d3SAlan Somers * 69821f1d3SAlan Somers * This software was developed by BFF Storage Systems, LLC under sponsorship 79821f1d3SAlan Somers * from the FreeBSD Foundation. 89821f1d3SAlan Somers * 99821f1d3SAlan Somers * Redistribution and use in source and binary forms, with or without 109821f1d3SAlan Somers * modification, are permitted provided that the following conditions 119821f1d3SAlan Somers * are met: 129821f1d3SAlan Somers * 1. Redistributions of source code must retain the above copyright 139821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer. 149821f1d3SAlan Somers * 2. Redistributions in binary form must reproduce the above copyright 159821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer in the 169821f1d3SAlan Somers * documentation and/or other materials provided with the distribution. 179821f1d3SAlan Somers * 189821f1d3SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 199821f1d3SAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 209821f1d3SAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219821f1d3SAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 229821f1d3SAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 239821f1d3SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 249821f1d3SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 259821f1d3SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 269821f1d3SAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 279821f1d3SAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 289821f1d3SAlan Somers * SUCH DAMAGE. 299821f1d3SAlan Somers */ 309821f1d3SAlan Somers 319821f1d3SAlan Somers extern "C" { 329821f1d3SAlan Somers #include <sys/param.h> 339821f1d3SAlan Somers #include <sys/mount.h> 347e0aac24SAlan Somers #include <semaphore.h> 359821f1d3SAlan Somers } 369821f1d3SAlan Somers 379821f1d3SAlan Somers #include "mockfs.hh" 389821f1d3SAlan Somers #include "utils.hh" 399821f1d3SAlan Somers 409821f1d3SAlan Somers using namespace testing; 419821f1d3SAlan Somers 429821f1d3SAlan Somers class Statfs: public FuseTest {}; 439821f1d3SAlan Somers 449821f1d3SAlan Somers TEST_F(Statfs, eio) 459821f1d3SAlan Somers { 469821f1d3SAlan Somers struct statfs statbuf; 479821f1d3SAlan Somers 489821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 499821f1d3SAlan Somers ResultOf([](auto in) { 5029edc611SAlan Somers return (in.header.opcode == FUSE_STATFS); 519821f1d3SAlan Somers }, Eq(true)), 529821f1d3SAlan Somers _) 539821f1d3SAlan Somers ).WillOnce(Invoke(ReturnErrno(EIO))); 549821f1d3SAlan Somers 559821f1d3SAlan Somers ASSERT_NE(0, statfs("mountpoint", &statbuf)); 569821f1d3SAlan Somers ASSERT_EQ(EIO, errno); 579821f1d3SAlan Somers } 589821f1d3SAlan Somers 599821f1d3SAlan Somers /* 609821f1d3SAlan Somers * When the daemon is dead but the filesystem is still mounted, fuse(4) fakes 619821f1d3SAlan Somers * the statfs(2) response, which is necessary for unmounting. 629821f1d3SAlan Somers */ 639821f1d3SAlan Somers TEST_F(Statfs, enotconn) 649821f1d3SAlan Somers { 659821f1d3SAlan Somers struct statfs statbuf; 669821f1d3SAlan Somers char mp[PATH_MAX]; 679821f1d3SAlan Somers 689821f1d3SAlan Somers m_mock->kill_daemon(); 699821f1d3SAlan Somers 709821f1d3SAlan Somers ASSERT_NE(NULL, getcwd(mp, PATH_MAX)) << strerror(errno); 719821f1d3SAlan Somers strlcat(mp, "/mountpoint", PATH_MAX); 729821f1d3SAlan Somers ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno); 739821f1d3SAlan Somers 749821f1d3SAlan Somers EXPECT_EQ(getuid(), statbuf.f_owner); 759821f1d3SAlan Somers EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename)); 769821f1d3SAlan Somers EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname)); 779821f1d3SAlan Somers EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname)); 789821f1d3SAlan Somers } 799821f1d3SAlan Somers 807e0aac24SAlan Somers static void* statfs_th(void* arg) { 817e0aac24SAlan Somers ssize_t r; 827e0aac24SAlan Somers struct statfs *sb = (struct statfs*)arg; 837e0aac24SAlan Somers 847e0aac24SAlan Somers r = statfs("mountpoint", sb); 857e0aac24SAlan Somers if (r >= 0) 867e0aac24SAlan Somers return 0; 877e0aac24SAlan Somers else 887e0aac24SAlan Somers return (void*)(intptr_t)errno; 897e0aac24SAlan Somers } 907e0aac24SAlan Somers 917e0aac24SAlan Somers /* 927e0aac24SAlan Somers * Like the enotconn test, but in this case the daemon dies after we send the 937e0aac24SAlan Somers * FUSE_STATFS operation but before we get a response. 947e0aac24SAlan Somers */ 957e0aac24SAlan Somers TEST_F(Statfs, enotconn_while_blocked) 967e0aac24SAlan Somers { 977e0aac24SAlan Somers struct statfs statbuf; 987e0aac24SAlan Somers void *thr0_value; 997e0aac24SAlan Somers pthread_t th0; 1007e0aac24SAlan Somers char mp[PATH_MAX]; 1017e0aac24SAlan Somers sem_t sem; 1027e0aac24SAlan Somers 1037e0aac24SAlan Somers ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno); 1047e0aac24SAlan Somers 1057e0aac24SAlan Somers EXPECT_CALL(*m_mock, process( 1067e0aac24SAlan Somers ResultOf([](auto in) { 10729edc611SAlan Somers return (in.header.opcode == FUSE_STATFS); 1087e0aac24SAlan Somers }, Eq(true)), 1097e0aac24SAlan Somers _) 1107e0aac24SAlan Somers ).WillOnce(Invoke([&](auto in __unused, auto &out __unused) { 1117e0aac24SAlan Somers sem_post(&sem); 1127e0aac24SAlan Somers /* Just block until the daemon dies */ 1137e0aac24SAlan Somers })); 1147e0aac24SAlan Somers 1157e0aac24SAlan Somers ASSERT_NE(NULL, getcwd(mp, PATH_MAX)) << strerror(errno); 1167e0aac24SAlan Somers strlcat(mp, "/mountpoint", PATH_MAX); 1177e0aac24SAlan Somers ASSERT_EQ(0, pthread_create(&th0, NULL, statfs_th, (void*)&statbuf)) 1187e0aac24SAlan Somers << strerror(errno); 1197e0aac24SAlan Somers 1207e0aac24SAlan Somers ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno); 1217e0aac24SAlan Somers m_mock->kill_daemon(); 1227e0aac24SAlan Somers 1237e0aac24SAlan Somers pthread_join(th0, &thr0_value); 1247e0aac24SAlan Somers ASSERT_EQ(0, (intptr_t)thr0_value); 1257e0aac24SAlan Somers 1267e0aac24SAlan Somers EXPECT_EQ(getuid(), statbuf.f_owner); 1277e0aac24SAlan Somers EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename)); 1287e0aac24SAlan Somers EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname)); 1297e0aac24SAlan Somers EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname)); 1307e0aac24SAlan Somers } 1317e0aac24SAlan Somers 1329821f1d3SAlan Somers TEST_F(Statfs, ok) 1339821f1d3SAlan Somers { 1349821f1d3SAlan Somers struct statfs statbuf; 1359821f1d3SAlan Somers char mp[PATH_MAX]; 1369821f1d3SAlan Somers 1379821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 1389821f1d3SAlan Somers ResultOf([](auto in) { 13929edc611SAlan Somers return (in.header.opcode == FUSE_STATFS); 1409821f1d3SAlan Somers }, Eq(true)), 1419821f1d3SAlan Somers _) 14229edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { 1439821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, statfs); 14429edc611SAlan Somers out.body.statfs.st.blocks = 1000; 14529edc611SAlan Somers out.body.statfs.st.bfree = 100; 14629edc611SAlan Somers out.body.statfs.st.bavail = 200; 14729edc611SAlan Somers out.body.statfs.st.files = 5; 14829edc611SAlan Somers out.body.statfs.st.ffree = 6; 14929edc611SAlan Somers out.body.statfs.st.namelen = 128; 15029edc611SAlan Somers out.body.statfs.st.frsize = 1024; 1519821f1d3SAlan Somers }))); 1529821f1d3SAlan Somers 1539821f1d3SAlan Somers ASSERT_NE(NULL, getcwd(mp, PATH_MAX)) << strerror(errno); 1549821f1d3SAlan Somers strlcat(mp, "/mountpoint", PATH_MAX); 1559821f1d3SAlan Somers ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno); 1569821f1d3SAlan Somers EXPECT_EQ(1024ul, statbuf.f_bsize); 1579821f1d3SAlan Somers /* 1589821f1d3SAlan Somers * fuse(4) ignores the filesystem's reported optimal transfer size, and 1599821f1d3SAlan Somers * chooses a size that works well with the rest of the system instead 1609821f1d3SAlan Somers */ 1619821f1d3SAlan Somers EXPECT_EQ(1000ul, statbuf.f_blocks); 1629821f1d3SAlan Somers EXPECT_EQ(100ul, statbuf.f_bfree); 1639821f1d3SAlan Somers EXPECT_EQ(200l, statbuf.f_bavail); 1649821f1d3SAlan Somers EXPECT_EQ(5ul, statbuf.f_files); 1659821f1d3SAlan Somers EXPECT_EQ(6l, statbuf.f_ffree); 1669821f1d3SAlan Somers EXPECT_EQ(128u, statbuf.f_namemax); 1679821f1d3SAlan Somers EXPECT_EQ(getuid(), statbuf.f_owner); 1689821f1d3SAlan Somers EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename)); 1699821f1d3SAlan Somers EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname)); 1709821f1d3SAlan Somers EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname)); 1719821f1d3SAlan Somers } 172