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 && 75*929acdb1SAlan Somers in.body.setlk.owner == (uint32_t)pid && 76*929acdb1SAlan Somers in.body.setlk.lk.start == start && 77*929acdb1SAlan Somers in.body.setlk.lk.end == end && 78*929acdb1SAlan Somers in.body.setlk.lk.type == type && 79*929acdb1SAlan Somers in.body.setlk.lk.pid == (uint64_t)pid); 80*929acdb1SAlan Somers }, Eq(true)), 81*929acdb1SAlan Somers _) 82*929acdb1SAlan Somers ).WillOnce(Invoke(ReturnErrno(err))); 83*929acdb1SAlan Somers } 84*929acdb1SAlan Somers void expect_setlkw(uint64_t ino, pid_t pid, uint64_t start, uint64_t end, 85*929acdb1SAlan Somers uint32_t type, int err) 86*929acdb1SAlan Somers { 87*929acdb1SAlan Somers EXPECT_CALL(*m_mock, process( 88*929acdb1SAlan Somers ResultOf([=](auto in) { 89*929acdb1SAlan Somers return (in.header.opcode == FUSE_SETLKW && 90*929acdb1SAlan Somers in.header.nodeid == ino && 91*929acdb1SAlan 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; 2319821f1d3SAlan Somers fl.l_pid = getpid(); 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; 2509821f1d3SAlan Somers pid_t pid = 1234; 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 && 25929edc611SAlan Somers in.body.getlk.owner == (uint32_t)pid && 26029edc611SAlan Somers in.body.getlk.lk.start == 10 && 26129edc611SAlan Somers in.body.getlk.lk.end == 1009 && 26229edc611SAlan Somers in.body.getlk.lk.type == F_RDLCK && 26329edc611SAlan Somers in.body.getlk.lk.pid == (uint64_t)pid); 2649821f1d3SAlan Somers }, Eq(true)), 2659821f1d3SAlan Somers _) 26629edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) { 2679821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, getlk); 26829edc611SAlan Somers out.body.getlk.lk = in.body.getlk.lk; 26929edc611SAlan Somers out.body.getlk.lk.type = F_UNLCK; 2709821f1d3SAlan Somers }))); 2719821f1d3SAlan Somers 2729821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 2739821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 2749821f1d3SAlan Somers fl.l_start = 10; 2759821f1d3SAlan Somers fl.l_len = 1000; 2769821f1d3SAlan Somers fl.l_pid = pid; 2779821f1d3SAlan Somers fl.l_type = F_RDLCK; 2789821f1d3SAlan Somers fl.l_whence = SEEK_SET; 2799821f1d3SAlan Somers fl.l_sysid = 0; 2809821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 2819821f1d3SAlan Somers ASSERT_EQ(F_UNLCK, fl.l_type); 2827fc0921dSAlan Somers leak(fd); 2839821f1d3SAlan Somers } 2849821f1d3SAlan Somers 2859821f1d3SAlan Somers /* A different pid does have a lock */ 286f067b609SAlan Somers TEST_F(Getlk, lock_exists) 2879821f1d3SAlan Somers { 2889821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2899821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2909821f1d3SAlan Somers uint64_t ino = 42; 2919821f1d3SAlan Somers struct flock fl; 2929821f1d3SAlan Somers int fd; 2939821f1d3SAlan Somers pid_t pid = 1234; 2949821f1d3SAlan Somers pid_t pid2 = 1235; 2959821f1d3SAlan Somers 2969821f1d3SAlan Somers expect_lookup(RELPATH, ino); 2979821f1d3SAlan Somers expect_open(ino, 0, 1); 2989821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 2999821f1d3SAlan Somers ResultOf([=](auto in) { 30029edc611SAlan Somers return (in.header.opcode == FUSE_GETLK && 30129edc611SAlan Somers in.header.nodeid == ino && 30229edc611SAlan Somers in.body.getlk.fh == FH && 30329edc611SAlan Somers in.body.getlk.owner == (uint32_t)pid && 30429edc611SAlan Somers in.body.getlk.lk.start == 10 && 30529edc611SAlan Somers in.body.getlk.lk.end == 1009 && 30629edc611SAlan Somers in.body.getlk.lk.type == F_RDLCK && 30729edc611SAlan Somers in.body.getlk.lk.pid == (uint64_t)pid); 3089821f1d3SAlan Somers }, Eq(true)), 3099821f1d3SAlan Somers _) 31029edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { 3119821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, getlk); 31229edc611SAlan Somers out.body.getlk.lk.start = 100; 31329edc611SAlan Somers out.body.getlk.lk.end = 199; 31429edc611SAlan Somers out.body.getlk.lk.type = F_WRLCK; 31529edc611SAlan Somers out.body.getlk.lk.pid = (uint32_t)pid2;; 3169821f1d3SAlan Somers }))); 3179821f1d3SAlan Somers 3189821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3199821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3209821f1d3SAlan Somers fl.l_start = 10; 3219821f1d3SAlan Somers fl.l_len = 1000; 3229821f1d3SAlan Somers fl.l_pid = pid; 3239821f1d3SAlan Somers fl.l_type = F_RDLCK; 3249821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3259821f1d3SAlan Somers fl.l_sysid = 0; 3269821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 3279821f1d3SAlan Somers EXPECT_EQ(100, fl.l_start); 3289821f1d3SAlan Somers EXPECT_EQ(100, fl.l_len); 3299821f1d3SAlan Somers EXPECT_EQ(pid2, fl.l_pid); 3309821f1d3SAlan Somers EXPECT_EQ(F_WRLCK, fl.l_type); 3319821f1d3SAlan Somers EXPECT_EQ(SEEK_SET, fl.l_whence); 3329821f1d3SAlan Somers EXPECT_EQ(0, fl.l_sysid); 3337fc0921dSAlan Somers leak(fd); 3349821f1d3SAlan Somers } 3359821f1d3SAlan Somers 3369821f1d3SAlan Somers /* 3379821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 3389821f1d3SAlan Somers * should fall back to local locks. 3399821f1d3SAlan Somers */ 3409821f1d3SAlan Somers TEST_F(SetlkFallback, local) 3419821f1d3SAlan Somers { 3429821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 3439821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 3449821f1d3SAlan Somers uint64_t ino = 42; 3459821f1d3SAlan Somers struct flock fl; 3469821f1d3SAlan Somers int fd; 3479821f1d3SAlan Somers 3489821f1d3SAlan Somers expect_lookup(RELPATH, ino); 3499821f1d3SAlan Somers expect_open(ino, 0, 1); 3509821f1d3SAlan Somers 3519821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3529821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3539821f1d3SAlan Somers fl.l_start = 10; 3549821f1d3SAlan Somers fl.l_len = 1000; 3559821f1d3SAlan Somers fl.l_pid = getpid(); 3569821f1d3SAlan Somers fl.l_type = F_RDLCK; 3579821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3589821f1d3SAlan Somers fl.l_sysid = 0; 3599821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 3607fc0921dSAlan Somers leak(fd); 3619821f1d3SAlan Somers } 3629821f1d3SAlan Somers 363*929acdb1SAlan Somers /* Clear a lock with FUSE_SETLK */ 364*929acdb1SAlan Somers TEST_F(Setlk, clear) 365*929acdb1SAlan Somers { 366*929acdb1SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 367*929acdb1SAlan Somers const char RELPATH[] = "some_file.txt"; 368*929acdb1SAlan Somers uint64_t ino = 42; 369*929acdb1SAlan Somers struct flock fl; 370*929acdb1SAlan Somers int fd; 371*929acdb1SAlan Somers pid_t pid = 1234; 372*929acdb1SAlan Somers 373*929acdb1SAlan Somers expect_lookup(RELPATH, ino); 374*929acdb1SAlan Somers expect_open(ino, 0, 1); 375*929acdb1SAlan Somers expect_setlk(ino, pid, 10, 1009, F_UNLCK, 0); 376*929acdb1SAlan Somers 377*929acdb1SAlan Somers fd = open(FULLPATH, O_RDWR); 378*929acdb1SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 379*929acdb1SAlan Somers fl.l_start = 10; 380*929acdb1SAlan Somers fl.l_len = 1000; 381*929acdb1SAlan Somers fl.l_pid = pid; 382*929acdb1SAlan Somers fl.l_type = F_UNLCK; 383*929acdb1SAlan Somers fl.l_whence = SEEK_SET; 384*929acdb1SAlan Somers fl.l_sysid = 0; 385*929acdb1SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 386*929acdb1SAlan Somers leak(fd); 387*929acdb1SAlan Somers } 388*929acdb1SAlan Somers 3899821f1d3SAlan Somers /* Set a new lock with FUSE_SETLK */ 390f067b609SAlan Somers TEST_F(Setlk, set) 3919821f1d3SAlan Somers { 3929821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 3939821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 3949821f1d3SAlan Somers uint64_t ino = 42; 3959821f1d3SAlan Somers struct flock fl; 3969821f1d3SAlan Somers int fd; 3979821f1d3SAlan Somers pid_t pid = 1234; 3989821f1d3SAlan Somers 3999821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4009821f1d3SAlan Somers expect_open(ino, 0, 1); 4018aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, 0); 4029821f1d3SAlan Somers 4039821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4049821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4059821f1d3SAlan Somers fl.l_start = 10; 4069821f1d3SAlan Somers fl.l_len = 1000; 4079821f1d3SAlan Somers fl.l_pid = pid; 4089821f1d3SAlan Somers fl.l_type = F_RDLCK; 4099821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4109821f1d3SAlan Somers fl.l_sysid = 0; 4119821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 4127fc0921dSAlan Somers leak(fd); 4139821f1d3SAlan Somers } 4149821f1d3SAlan Somers 4159821f1d3SAlan Somers /* l_len = 0 is a flag value that means to lock until EOF */ 416f067b609SAlan Somers TEST_F(Setlk, set_eof) 4179821f1d3SAlan Somers { 4189821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4199821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4209821f1d3SAlan Somers uint64_t ino = 42; 4219821f1d3SAlan Somers struct flock fl; 4229821f1d3SAlan Somers int fd; 4239821f1d3SAlan Somers pid_t pid = 1234; 4249821f1d3SAlan Somers 4259821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4269821f1d3SAlan Somers expect_open(ino, 0, 1); 4278aa24ed3SAlan Somers expect_setlk(ino, pid, 10, OFFSET_MAX, F_RDLCK, 0); 4289821f1d3SAlan Somers 4299821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4309821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4319821f1d3SAlan Somers fl.l_start = 10; 4329821f1d3SAlan Somers fl.l_len = 0; 4339821f1d3SAlan Somers fl.l_pid = pid; 4349821f1d3SAlan Somers fl.l_type = F_RDLCK; 4359821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4369821f1d3SAlan Somers fl.l_sysid = 0; 4379821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 4387fc0921dSAlan Somers leak(fd); 4399821f1d3SAlan Somers } 4409821f1d3SAlan Somers 4419821f1d3SAlan Somers /* Fail to set a new lock with FUSE_SETLK due to a conflict */ 442f067b609SAlan Somers TEST_F(Setlk, eagain) 4439821f1d3SAlan Somers { 4449821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4459821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4469821f1d3SAlan Somers uint64_t ino = 42; 4479821f1d3SAlan Somers struct flock fl; 4489821f1d3SAlan Somers int fd; 4499821f1d3SAlan Somers pid_t pid = 1234; 4509821f1d3SAlan Somers 4519821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4529821f1d3SAlan Somers expect_open(ino, 0, 1); 4538aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, EAGAIN); 4549821f1d3SAlan Somers 4559821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4569821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4579821f1d3SAlan Somers fl.l_start = 10; 4589821f1d3SAlan Somers fl.l_len = 1000; 4599821f1d3SAlan Somers fl.l_pid = pid; 4609821f1d3SAlan Somers fl.l_type = F_RDLCK; 4619821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4629821f1d3SAlan Somers fl.l_sysid = 0; 4639821f1d3SAlan Somers ASSERT_EQ(-1, fcntl(fd, F_SETLK, &fl)); 4649821f1d3SAlan Somers ASSERT_EQ(EAGAIN, errno); 4657fc0921dSAlan Somers leak(fd); 4669821f1d3SAlan Somers } 4679821f1d3SAlan Somers 4689821f1d3SAlan Somers /* 4699821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 4709821f1d3SAlan Somers * should fall back to local locks. 4719821f1d3SAlan Somers */ 4729821f1d3SAlan Somers TEST_F(SetlkwFallback, local) 4739821f1d3SAlan Somers { 4749821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4759821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4769821f1d3SAlan Somers uint64_t ino = 42; 4779821f1d3SAlan Somers struct flock fl; 4789821f1d3SAlan Somers int fd; 4799821f1d3SAlan Somers 4809821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4819821f1d3SAlan Somers expect_open(ino, 0, 1); 4829821f1d3SAlan Somers 4839821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4849821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4859821f1d3SAlan Somers fl.l_start = 10; 4869821f1d3SAlan Somers fl.l_len = 1000; 4879821f1d3SAlan Somers fl.l_pid = getpid(); 4889821f1d3SAlan Somers fl.l_type = F_RDLCK; 4899821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4909821f1d3SAlan Somers fl.l_sysid = 0; 4919821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno); 4927fc0921dSAlan Somers leak(fd); 4939821f1d3SAlan Somers } 4949821f1d3SAlan Somers 4959821f1d3SAlan Somers /* 4969821f1d3SAlan Somers * Set a new lock with FUSE_SETLK. If the lock is not available, then the 4979821f1d3SAlan Somers * command should block. But to the kernel, that's the same as just being 4989821f1d3SAlan Somers * slow, so we don't need a separate test method 4999821f1d3SAlan Somers */ 500f067b609SAlan Somers TEST_F(Setlkw, set) 5019821f1d3SAlan Somers { 5029821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 5039821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 5049821f1d3SAlan Somers uint64_t ino = 42; 5059821f1d3SAlan Somers struct flock fl; 5069821f1d3SAlan Somers int fd; 5079821f1d3SAlan Somers pid_t pid = 1234; 5089821f1d3SAlan Somers 5099821f1d3SAlan Somers expect_lookup(RELPATH, ino); 5109821f1d3SAlan Somers expect_open(ino, 0, 1); 511*929acdb1SAlan Somers expect_setlkw(ino, pid, 10, 1009, F_RDLCK, 0); 5129821f1d3SAlan Somers 5139821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 5149821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 5159821f1d3SAlan Somers fl.l_start = 10; 5169821f1d3SAlan Somers fl.l_len = 1000; 5179821f1d3SAlan Somers fl.l_pid = pid; 5189821f1d3SAlan Somers fl.l_type = F_RDLCK; 5199821f1d3SAlan Somers fl.l_whence = SEEK_SET; 5209821f1d3SAlan Somers fl.l_sysid = 0; 5219821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno); 5227fc0921dSAlan Somers leak(fd); 5239821f1d3SAlan Somers } 524