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. 291fa8ebfbSAlan Somers * 301fa8ebfbSAlan Somers * $FreeBSD$ 319821f1d3SAlan Somers */ 329821f1d3SAlan Somers 339821f1d3SAlan Somers extern "C" { 348aa24ed3SAlan Somers #include <sys/file.h> 359821f1d3SAlan Somers #include <fcntl.h> 369821f1d3SAlan Somers } 379821f1d3SAlan Somers 389821f1d3SAlan Somers #include "mockfs.hh" 399821f1d3SAlan Somers #include "utils.hh" 409821f1d3SAlan Somers 419821f1d3SAlan Somers /* This flag value should probably be defined in fuse_kernel.h */ 429821f1d3SAlan Somers #define OFFSET_MAX 0x7fffffffffffffffLL 439821f1d3SAlan Somers 449821f1d3SAlan Somers using namespace testing; 459821f1d3SAlan Somers 469821f1d3SAlan Somers /* For testing filesystems without posix locking support */ 479821f1d3SAlan Somers class Fallback: public FuseTest { 489821f1d3SAlan Somers public: 499821f1d3SAlan Somers 509821f1d3SAlan Somers void expect_lookup(const char *relpath, uint64_t ino) 519821f1d3SAlan Somers { 529821f1d3SAlan Somers FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1); 539821f1d3SAlan Somers } 549821f1d3SAlan Somers 559821f1d3SAlan Somers }; 569821f1d3SAlan Somers 579821f1d3SAlan Somers /* For testing filesystems with posix locking support */ 589821f1d3SAlan Somers class Locks: public Fallback { 599821f1d3SAlan Somers virtual void SetUp() { 609821f1d3SAlan Somers m_init_flags = FUSE_POSIX_LOCKS; 619821f1d3SAlan Somers Fallback::SetUp(); 629821f1d3SAlan Somers } 639821f1d3SAlan Somers }; 649821f1d3SAlan Somers 658aa24ed3SAlan Somers class Fcntl: public Locks { 668aa24ed3SAlan Somers public: 678aa24ed3SAlan Somers void expect_setlk(uint64_t ino, pid_t pid, uint64_t start, uint64_t end, 688aa24ed3SAlan Somers uint32_t type, int err) 698aa24ed3SAlan Somers { 708aa24ed3SAlan Somers EXPECT_CALL(*m_mock, process( 718aa24ed3SAlan Somers ResultOf([=](auto in) { 728aa24ed3SAlan Somers return (in.header.opcode == FUSE_SETLK && 738aa24ed3SAlan Somers in.header.nodeid == ino && 748aa24ed3SAlan Somers in.body.setlk.fh == FH && 75929acdb1SAlan Somers in.body.setlk.owner == (uint32_t)pid && 76929acdb1SAlan Somers in.body.setlk.lk.start == start && 77929acdb1SAlan Somers in.body.setlk.lk.end == end && 78929acdb1SAlan Somers in.body.setlk.lk.type == type && 79929acdb1SAlan Somers in.body.setlk.lk.pid == (uint64_t)pid); 80929acdb1SAlan Somers }, Eq(true)), 81929acdb1SAlan Somers _) 82929acdb1SAlan Somers ).WillOnce(Invoke(ReturnErrno(err))); 83929acdb1SAlan Somers } 84929acdb1SAlan Somers void expect_setlkw(uint64_t ino, pid_t pid, uint64_t start, uint64_t end, 85929acdb1SAlan Somers uint32_t type, int err) 86929acdb1SAlan Somers { 87929acdb1SAlan Somers EXPECT_CALL(*m_mock, process( 88929acdb1SAlan Somers ResultOf([=](auto in) { 89929acdb1SAlan Somers return (in.header.opcode == FUSE_SETLKW && 90929acdb1SAlan Somers in.header.nodeid == ino && 91929acdb1SAlan Somers in.body.setlkw.fh == FH && 928aa24ed3SAlan Somers in.body.setlkw.owner == (uint32_t)pid && 938aa24ed3SAlan Somers in.body.setlkw.lk.start == start && 948aa24ed3SAlan Somers in.body.setlkw.lk.end == end && 958aa24ed3SAlan Somers in.body.setlkw.lk.type == type && 968aa24ed3SAlan Somers in.body.setlkw.lk.pid == (uint64_t)pid); 978aa24ed3SAlan Somers }, Eq(true)), 988aa24ed3SAlan Somers _) 998aa24ed3SAlan Somers ).WillOnce(Invoke(ReturnErrno(err))); 1008aa24ed3SAlan Somers } 1018aa24ed3SAlan Somers }; 1028aa24ed3SAlan Somers 1038aa24ed3SAlan Somers class Flock: public Locks { 1048aa24ed3SAlan Somers public: 1058aa24ed3SAlan Somers void expect_setlk(uint64_t ino, uint32_t type, int err) 1068aa24ed3SAlan Somers { 1078aa24ed3SAlan Somers EXPECT_CALL(*m_mock, process( 1088aa24ed3SAlan Somers ResultOf([=](auto in) { 1098aa24ed3SAlan Somers return (in.header.opcode == FUSE_SETLK && 1108aa24ed3SAlan Somers in.header.nodeid == ino && 1118aa24ed3SAlan Somers in.body.setlk.fh == FH && 1128aa24ed3SAlan Somers /* 1138aa24ed3SAlan Somers * The owner should be set to the address of 1148aa24ed3SAlan Somers * the vnode. That's hard to verify. 1158aa24ed3SAlan Somers */ 1168aa24ed3SAlan Somers /* in.body.setlk.owner == ??? && */ 1178aa24ed3SAlan Somers in.body.setlk.lk.type == type); 1188aa24ed3SAlan Somers }, Eq(true)), 1198aa24ed3SAlan Somers _) 1208aa24ed3SAlan Somers ).WillOnce(Invoke(ReturnErrno(err))); 1218aa24ed3SAlan Somers } 1228aa24ed3SAlan Somers }; 1238aa24ed3SAlan Somers 1248aa24ed3SAlan Somers class FlockFallback: public Fallback {}; 1259821f1d3SAlan Somers class GetlkFallback: public Fallback {}; 1268aa24ed3SAlan Somers class Getlk: public Fcntl {}; 1279821f1d3SAlan Somers class SetlkFallback: public Fallback {}; 1288aa24ed3SAlan Somers class Setlk: public Fcntl {}; 1299821f1d3SAlan Somers class SetlkwFallback: public Fallback {}; 1308aa24ed3SAlan Somers class Setlkw: public Fcntl {}; 1318aa24ed3SAlan Somers 1328aa24ed3SAlan Somers /* 1338aa24ed3SAlan Somers * If the fuse filesystem does not support flock locks, then the kernel should 1348aa24ed3SAlan Somers * fall back to local locks. 1358aa24ed3SAlan Somers */ 1368aa24ed3SAlan Somers TEST_F(FlockFallback, local) 1378aa24ed3SAlan Somers { 1388aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 1398aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 1408aa24ed3SAlan Somers uint64_t ino = 42; 1418aa24ed3SAlan Somers int fd; 1428aa24ed3SAlan Somers 1438aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 1448aa24ed3SAlan Somers expect_open(ino, 0, 1); 1458aa24ed3SAlan Somers 1468aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 1478aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 1488aa24ed3SAlan Somers ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno); 1497fc0921dSAlan Somers leak(fd); 1508aa24ed3SAlan Somers } 1518aa24ed3SAlan Somers 1528aa24ed3SAlan Somers /* 1538aa24ed3SAlan Somers * Even if the fuse file system supports POSIX locks, we must implement flock 1548aa24ed3SAlan Somers * locks locally until protocol 7.17. Protocol 7.9 added partial buggy support 1558aa24ed3SAlan Somers * but we won't implement that. 1568aa24ed3SAlan Somers */ 1578aa24ed3SAlan Somers TEST_F(Flock, local) 1588aa24ed3SAlan Somers { 1598aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 1608aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 1618aa24ed3SAlan Somers uint64_t ino = 42; 1628aa24ed3SAlan Somers int fd; 1638aa24ed3SAlan Somers 1648aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 1658aa24ed3SAlan Somers expect_open(ino, 0, 1); 1668aa24ed3SAlan Somers 1678aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 1688aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 1698aa24ed3SAlan Somers ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno); 1707fc0921dSAlan Somers leak(fd); 1718aa24ed3SAlan Somers } 1728aa24ed3SAlan Somers 1738aa24ed3SAlan Somers /* Set a new flock lock with FUSE_SETLK */ 1748aa24ed3SAlan Somers /* TODO: enable after upgrading to protocol 7.17 */ 1758aa24ed3SAlan Somers TEST_F(Flock, DISABLED_set) 1768aa24ed3SAlan Somers { 1778aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 1788aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 1798aa24ed3SAlan Somers uint64_t ino = 42; 1808aa24ed3SAlan Somers int fd; 1818aa24ed3SAlan Somers 1828aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 1838aa24ed3SAlan Somers expect_open(ino, 0, 1); 1848aa24ed3SAlan Somers expect_setlk(ino, F_WRLCK, 0); 1858aa24ed3SAlan Somers 1868aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 1878aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 1888aa24ed3SAlan Somers ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno); 1897fc0921dSAlan Somers leak(fd); 1908aa24ed3SAlan Somers } 1918aa24ed3SAlan Somers 1928aa24ed3SAlan Somers /* Fail to set a flock lock in non-blocking mode */ 1938aa24ed3SAlan Somers /* TODO: enable after upgrading to protocol 7.17 */ 1948aa24ed3SAlan Somers TEST_F(Flock, DISABLED_eagain) 1958aa24ed3SAlan Somers { 1968aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 1978aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 1988aa24ed3SAlan Somers uint64_t ino = 42; 1998aa24ed3SAlan Somers int fd; 2008aa24ed3SAlan Somers 2018aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 2028aa24ed3SAlan Somers expect_open(ino, 0, 1); 2038aa24ed3SAlan Somers expect_setlk(ino, F_WRLCK, EAGAIN); 2048aa24ed3SAlan Somers 2058aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 2068aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 2078aa24ed3SAlan Somers ASSERT_NE(0, flock(fd, LOCK_EX | LOCK_NB)); 2088aa24ed3SAlan Somers ASSERT_EQ(EAGAIN, errno); 2097fc0921dSAlan Somers leak(fd); 2108aa24ed3SAlan Somers } 2119821f1d3SAlan Somers 2129821f1d3SAlan Somers /* 2139821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 2149821f1d3SAlan Somers * should fall back to local locks. 2159821f1d3SAlan Somers */ 2169821f1d3SAlan Somers TEST_F(GetlkFallback, local) 2179821f1d3SAlan Somers { 2189821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2199821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2209821f1d3SAlan Somers uint64_t ino = 42; 2219821f1d3SAlan Somers struct flock fl; 2229821f1d3SAlan Somers int fd; 2239821f1d3SAlan Somers 2249821f1d3SAlan Somers expect_lookup(RELPATH, ino); 2259821f1d3SAlan Somers expect_open(ino, 0, 1); 2269821f1d3SAlan Somers 2279821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 2289821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 2299821f1d3SAlan Somers fl.l_start = 10; 2309821f1d3SAlan Somers fl.l_len = 1000; 231*18b19f8cSAlan Somers fl.l_pid = 0; 2329821f1d3SAlan Somers fl.l_type = F_RDLCK; 2339821f1d3SAlan Somers fl.l_whence = SEEK_SET; 2349821f1d3SAlan Somers fl.l_sysid = 0; 2359821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 2367fc0921dSAlan Somers leak(fd); 2379821f1d3SAlan Somers } 2389821f1d3SAlan Somers 2399821f1d3SAlan Somers /* 2409821f1d3SAlan Somers * If the filesystem has no locks that fit the description, the filesystem 2419821f1d3SAlan Somers * should return F_UNLCK 2429821f1d3SAlan Somers */ 243f067b609SAlan Somers TEST_F(Getlk, no_locks) 2449821f1d3SAlan Somers { 2459821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2469821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2479821f1d3SAlan Somers uint64_t ino = 42; 2489821f1d3SAlan Somers struct flock fl; 2499821f1d3SAlan Somers int fd; 250*18b19f8cSAlan Somers pid_t pid = getpid(); 2519821f1d3SAlan Somers 2529821f1d3SAlan Somers expect_lookup(RELPATH, ino); 2539821f1d3SAlan Somers expect_open(ino, 0, 1); 2549821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 2559821f1d3SAlan Somers ResultOf([=](auto in) { 25629edc611SAlan Somers return (in.header.opcode == FUSE_GETLK && 25729edc611SAlan Somers in.header.nodeid == ino && 25829edc611SAlan Somers in.body.getlk.fh == FH && 259*18b19f8cSAlan Somers /* 260*18b19f8cSAlan Somers * Though it seems useless, libfuse expects the 261*18b19f8cSAlan Somers * owner and pid fields to be set during 262*18b19f8cSAlan Somers * FUSE_GETLK. 263*18b19f8cSAlan Somers */ 26429edc611SAlan Somers in.body.getlk.owner == (uint32_t)pid && 265*18b19f8cSAlan Somers in.body.getlk.lk.pid == (uint64_t)pid && 26629edc611SAlan Somers in.body.getlk.lk.start == 10 && 26729edc611SAlan Somers in.body.getlk.lk.end == 1009 && 268*18b19f8cSAlan Somers in.body.getlk.lk.type == F_RDLCK); 2699821f1d3SAlan Somers }, Eq(true)), 2709821f1d3SAlan Somers _) 27129edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) { 2729821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, getlk); 27329edc611SAlan Somers out.body.getlk.lk = in.body.getlk.lk; 27429edc611SAlan Somers out.body.getlk.lk.type = F_UNLCK; 2759821f1d3SAlan Somers }))); 2769821f1d3SAlan Somers 2779821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 2789821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 2799821f1d3SAlan Somers fl.l_start = 10; 2809821f1d3SAlan Somers fl.l_len = 1000; 281*18b19f8cSAlan Somers fl.l_pid = 0; 2829821f1d3SAlan Somers fl.l_type = F_RDLCK; 2839821f1d3SAlan Somers fl.l_whence = SEEK_SET; 2849821f1d3SAlan Somers fl.l_sysid = 0; 2859821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 2869821f1d3SAlan Somers ASSERT_EQ(F_UNLCK, fl.l_type); 2877fc0921dSAlan Somers leak(fd); 2889821f1d3SAlan Somers } 2899821f1d3SAlan Somers 2909821f1d3SAlan Somers /* A different pid does have a lock */ 291f067b609SAlan Somers TEST_F(Getlk, lock_exists) 2929821f1d3SAlan Somers { 2939821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2949821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2959821f1d3SAlan Somers uint64_t ino = 42; 2969821f1d3SAlan Somers struct flock fl; 2979821f1d3SAlan Somers int fd; 298*18b19f8cSAlan Somers pid_t pid = getpid(); 2999821f1d3SAlan Somers pid_t pid2 = 1235; 3009821f1d3SAlan Somers 3019821f1d3SAlan Somers expect_lookup(RELPATH, ino); 3029821f1d3SAlan Somers expect_open(ino, 0, 1); 3039821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 3049821f1d3SAlan Somers ResultOf([=](auto in) { 30529edc611SAlan Somers return (in.header.opcode == FUSE_GETLK && 30629edc611SAlan Somers in.header.nodeid == ino && 30729edc611SAlan Somers in.body.getlk.fh == FH && 308*18b19f8cSAlan Somers /* 309*18b19f8cSAlan Somers * Though it seems useless, libfuse expects the 310*18b19f8cSAlan Somers * owner and pid fields to be set during 311*18b19f8cSAlan Somers * FUSE_GETLK. 312*18b19f8cSAlan Somers */ 31329edc611SAlan Somers in.body.getlk.owner == (uint32_t)pid && 314*18b19f8cSAlan Somers in.body.getlk.lk.pid == (uint64_t)pid && 31529edc611SAlan Somers in.body.getlk.lk.start == 10 && 31629edc611SAlan Somers in.body.getlk.lk.end == 1009 && 317*18b19f8cSAlan Somers in.body.getlk.lk.type == F_RDLCK); 3189821f1d3SAlan Somers }, Eq(true)), 3199821f1d3SAlan Somers _) 32029edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { 3219821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, getlk); 32229edc611SAlan Somers out.body.getlk.lk.start = 100; 32329edc611SAlan Somers out.body.getlk.lk.end = 199; 32429edc611SAlan Somers out.body.getlk.lk.type = F_WRLCK; 32529edc611SAlan Somers out.body.getlk.lk.pid = (uint32_t)pid2;; 3269821f1d3SAlan Somers }))); 3279821f1d3SAlan Somers 3289821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3299821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3309821f1d3SAlan Somers fl.l_start = 10; 3319821f1d3SAlan Somers fl.l_len = 1000; 332*18b19f8cSAlan Somers fl.l_pid = 0; 3339821f1d3SAlan Somers fl.l_type = F_RDLCK; 3349821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3359821f1d3SAlan Somers fl.l_sysid = 0; 3369821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 3379821f1d3SAlan Somers EXPECT_EQ(100, fl.l_start); 3389821f1d3SAlan Somers EXPECT_EQ(100, fl.l_len); 3399821f1d3SAlan Somers EXPECT_EQ(pid2, fl.l_pid); 3409821f1d3SAlan Somers EXPECT_EQ(F_WRLCK, fl.l_type); 3419821f1d3SAlan Somers EXPECT_EQ(SEEK_SET, fl.l_whence); 3429821f1d3SAlan Somers EXPECT_EQ(0, fl.l_sysid); 3437fc0921dSAlan Somers leak(fd); 3449821f1d3SAlan Somers } 3459821f1d3SAlan Somers 3469821f1d3SAlan Somers /* 3479821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 3489821f1d3SAlan Somers * should fall back to local locks. 3499821f1d3SAlan Somers */ 3509821f1d3SAlan Somers TEST_F(SetlkFallback, local) 3519821f1d3SAlan Somers { 3529821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 3539821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 3549821f1d3SAlan Somers uint64_t ino = 42; 3559821f1d3SAlan Somers struct flock fl; 3569821f1d3SAlan Somers int fd; 3579821f1d3SAlan Somers 3589821f1d3SAlan Somers expect_lookup(RELPATH, ino); 3599821f1d3SAlan Somers expect_open(ino, 0, 1); 3609821f1d3SAlan Somers 3619821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3629821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3639821f1d3SAlan Somers fl.l_start = 10; 3649821f1d3SAlan Somers fl.l_len = 1000; 3659821f1d3SAlan Somers fl.l_pid = getpid(); 3669821f1d3SAlan Somers fl.l_type = F_RDLCK; 3679821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3689821f1d3SAlan Somers fl.l_sysid = 0; 3699821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 3707fc0921dSAlan Somers leak(fd); 3719821f1d3SAlan Somers } 3729821f1d3SAlan Somers 373929acdb1SAlan Somers /* Clear a lock with FUSE_SETLK */ 374929acdb1SAlan Somers TEST_F(Setlk, clear) 375929acdb1SAlan Somers { 376929acdb1SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 377929acdb1SAlan Somers const char RELPATH[] = "some_file.txt"; 378929acdb1SAlan Somers uint64_t ino = 42; 379929acdb1SAlan Somers struct flock fl; 380929acdb1SAlan Somers int fd; 381*18b19f8cSAlan Somers pid_t pid = getpid(); 382929acdb1SAlan Somers 383929acdb1SAlan Somers expect_lookup(RELPATH, ino); 384929acdb1SAlan Somers expect_open(ino, 0, 1); 385929acdb1SAlan Somers expect_setlk(ino, pid, 10, 1009, F_UNLCK, 0); 386929acdb1SAlan Somers 387929acdb1SAlan Somers fd = open(FULLPATH, O_RDWR); 388929acdb1SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 389929acdb1SAlan Somers fl.l_start = 10; 390929acdb1SAlan Somers fl.l_len = 1000; 391*18b19f8cSAlan Somers fl.l_pid = 0; 392929acdb1SAlan Somers fl.l_type = F_UNLCK; 393929acdb1SAlan Somers fl.l_whence = SEEK_SET; 394929acdb1SAlan Somers fl.l_sysid = 0; 395929acdb1SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 396929acdb1SAlan Somers leak(fd); 397929acdb1SAlan Somers } 398929acdb1SAlan Somers 3999821f1d3SAlan Somers /* Set a new lock with FUSE_SETLK */ 400f067b609SAlan Somers TEST_F(Setlk, set) 4019821f1d3SAlan Somers { 4029821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4039821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4049821f1d3SAlan Somers uint64_t ino = 42; 4059821f1d3SAlan Somers struct flock fl; 4069821f1d3SAlan Somers int fd; 407*18b19f8cSAlan Somers pid_t pid = getpid(); 4089821f1d3SAlan Somers 4099821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4109821f1d3SAlan Somers expect_open(ino, 0, 1); 4118aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, 0); 4129821f1d3SAlan Somers 4139821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4149821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4159821f1d3SAlan Somers fl.l_start = 10; 4169821f1d3SAlan Somers fl.l_len = 1000; 417*18b19f8cSAlan Somers fl.l_pid = 0; 4189821f1d3SAlan Somers fl.l_type = F_RDLCK; 4199821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4209821f1d3SAlan Somers fl.l_sysid = 0; 4219821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 4227fc0921dSAlan Somers leak(fd); 4239821f1d3SAlan Somers } 4249821f1d3SAlan Somers 4259821f1d3SAlan Somers /* l_len = 0 is a flag value that means to lock until EOF */ 426f067b609SAlan Somers TEST_F(Setlk, set_eof) 4279821f1d3SAlan Somers { 4289821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4299821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4309821f1d3SAlan Somers uint64_t ino = 42; 4319821f1d3SAlan Somers struct flock fl; 4329821f1d3SAlan Somers int fd; 433*18b19f8cSAlan Somers pid_t pid = getpid(); 4349821f1d3SAlan Somers 4359821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4369821f1d3SAlan Somers expect_open(ino, 0, 1); 4378aa24ed3SAlan Somers expect_setlk(ino, pid, 10, OFFSET_MAX, F_RDLCK, 0); 4389821f1d3SAlan Somers 4399821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4409821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4419821f1d3SAlan Somers fl.l_start = 10; 4429821f1d3SAlan Somers fl.l_len = 0; 443*18b19f8cSAlan Somers fl.l_pid = 0; 4449821f1d3SAlan Somers fl.l_type = F_RDLCK; 4459821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4469821f1d3SAlan Somers fl.l_sysid = 0; 4479821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 4487fc0921dSAlan Somers leak(fd); 4499821f1d3SAlan Somers } 4509821f1d3SAlan Somers 4519821f1d3SAlan Somers /* Fail to set a new lock with FUSE_SETLK due to a conflict */ 452f067b609SAlan Somers TEST_F(Setlk, eagain) 4539821f1d3SAlan Somers { 4549821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4559821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4569821f1d3SAlan Somers uint64_t ino = 42; 4579821f1d3SAlan Somers struct flock fl; 4589821f1d3SAlan Somers int fd; 459*18b19f8cSAlan Somers pid_t pid = getpid(); 4609821f1d3SAlan Somers 4619821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4629821f1d3SAlan Somers expect_open(ino, 0, 1); 4638aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, EAGAIN); 4649821f1d3SAlan Somers 4659821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4669821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4679821f1d3SAlan Somers fl.l_start = 10; 4689821f1d3SAlan Somers fl.l_len = 1000; 469*18b19f8cSAlan Somers fl.l_pid = 0; 4709821f1d3SAlan Somers fl.l_type = F_RDLCK; 4719821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4729821f1d3SAlan Somers fl.l_sysid = 0; 4739821f1d3SAlan Somers ASSERT_EQ(-1, fcntl(fd, F_SETLK, &fl)); 4749821f1d3SAlan Somers ASSERT_EQ(EAGAIN, errno); 4757fc0921dSAlan Somers leak(fd); 4769821f1d3SAlan Somers } 4779821f1d3SAlan Somers 4789821f1d3SAlan Somers /* 4799821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 4809821f1d3SAlan Somers * should fall back to local locks. 4819821f1d3SAlan Somers */ 4829821f1d3SAlan Somers TEST_F(SetlkwFallback, local) 4839821f1d3SAlan Somers { 4849821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4859821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4869821f1d3SAlan Somers uint64_t ino = 42; 4879821f1d3SAlan Somers struct flock fl; 4889821f1d3SAlan Somers int fd; 4899821f1d3SAlan Somers 4909821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4919821f1d3SAlan Somers expect_open(ino, 0, 1); 4929821f1d3SAlan Somers 4939821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4949821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4959821f1d3SAlan Somers fl.l_start = 10; 4969821f1d3SAlan Somers fl.l_len = 1000; 497*18b19f8cSAlan Somers fl.l_pid = 0; 4989821f1d3SAlan Somers fl.l_type = F_RDLCK; 4999821f1d3SAlan Somers fl.l_whence = SEEK_SET; 5009821f1d3SAlan Somers fl.l_sysid = 0; 5019821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno); 5027fc0921dSAlan Somers leak(fd); 5039821f1d3SAlan Somers } 5049821f1d3SAlan Somers 5059821f1d3SAlan Somers /* 5069821f1d3SAlan Somers * Set a new lock with FUSE_SETLK. If the lock is not available, then the 5079821f1d3SAlan Somers * command should block. But to the kernel, that's the same as just being 5089821f1d3SAlan Somers * slow, so we don't need a separate test method 5099821f1d3SAlan Somers */ 510f067b609SAlan Somers TEST_F(Setlkw, set) 5119821f1d3SAlan Somers { 5129821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 5139821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 5149821f1d3SAlan Somers uint64_t ino = 42; 5159821f1d3SAlan Somers struct flock fl; 5169821f1d3SAlan Somers int fd; 517*18b19f8cSAlan Somers pid_t pid = getpid(); 5189821f1d3SAlan Somers 5199821f1d3SAlan Somers expect_lookup(RELPATH, ino); 5209821f1d3SAlan Somers expect_open(ino, 0, 1); 521929acdb1SAlan Somers expect_setlkw(ino, pid, 10, 1009, F_RDLCK, 0); 5229821f1d3SAlan Somers 5239821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 5249821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 5259821f1d3SAlan Somers fl.l_start = 10; 5269821f1d3SAlan Somers fl.l_len = 1000; 527*18b19f8cSAlan Somers fl.l_pid = 0; 5289821f1d3SAlan Somers fl.l_type = F_RDLCK; 5299821f1d3SAlan Somers fl.l_whence = SEEK_SET; 5309821f1d3SAlan Somers fl.l_sysid = 0; 5319821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno); 5327fc0921dSAlan Somers leak(fd); 5339821f1d3SAlan Somers } 534