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" { 32*8aa24ed3SAlan Somers #include <sys/file.h> 339821f1d3SAlan Somers #include <fcntl.h> 349821f1d3SAlan Somers } 359821f1d3SAlan Somers 369821f1d3SAlan Somers #include "mockfs.hh" 379821f1d3SAlan Somers #include "utils.hh" 389821f1d3SAlan Somers 399821f1d3SAlan Somers /* This flag value should probably be defined in fuse_kernel.h */ 409821f1d3SAlan Somers #define OFFSET_MAX 0x7fffffffffffffffLL 419821f1d3SAlan Somers 429821f1d3SAlan Somers using namespace testing; 439821f1d3SAlan Somers 449821f1d3SAlan Somers /* For testing filesystems without posix locking support */ 459821f1d3SAlan Somers class Fallback: public FuseTest { 469821f1d3SAlan Somers public: 479821f1d3SAlan Somers 489821f1d3SAlan Somers void expect_lookup(const char *relpath, uint64_t ino) 499821f1d3SAlan Somers { 509821f1d3SAlan Somers FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1); 519821f1d3SAlan Somers } 529821f1d3SAlan Somers 539821f1d3SAlan Somers }; 549821f1d3SAlan Somers 559821f1d3SAlan Somers /* For testing filesystems with posix locking support */ 569821f1d3SAlan Somers class Locks: public Fallback { 579821f1d3SAlan Somers virtual void SetUp() { 589821f1d3SAlan Somers m_init_flags = FUSE_POSIX_LOCKS; 599821f1d3SAlan Somers Fallback::SetUp(); 609821f1d3SAlan Somers } 619821f1d3SAlan Somers }; 629821f1d3SAlan Somers 63*8aa24ed3SAlan Somers class Fcntl: public Locks { 64*8aa24ed3SAlan Somers public: 65*8aa24ed3SAlan Somers void expect_setlk(uint64_t ino, pid_t pid, uint64_t start, uint64_t end, 66*8aa24ed3SAlan Somers uint32_t type, int err) 67*8aa24ed3SAlan Somers { 68*8aa24ed3SAlan Somers EXPECT_CALL(*m_mock, process( 69*8aa24ed3SAlan Somers ResultOf([=](auto in) { 70*8aa24ed3SAlan Somers return (in.header.opcode == FUSE_SETLK && 71*8aa24ed3SAlan Somers in.header.nodeid == ino && 72*8aa24ed3SAlan Somers in.body.setlk.fh == FH && 73*8aa24ed3SAlan Somers in.body.setlkw.owner == (uint32_t)pid && 74*8aa24ed3SAlan Somers in.body.setlkw.lk.start == start && 75*8aa24ed3SAlan Somers in.body.setlkw.lk.end == end && 76*8aa24ed3SAlan Somers in.body.setlkw.lk.type == type && 77*8aa24ed3SAlan Somers in.body.setlkw.lk.pid == (uint64_t)pid); 78*8aa24ed3SAlan Somers }, Eq(true)), 79*8aa24ed3SAlan Somers _) 80*8aa24ed3SAlan Somers ).WillOnce(Invoke(ReturnErrno(err))); 81*8aa24ed3SAlan Somers } 82*8aa24ed3SAlan Somers }; 83*8aa24ed3SAlan Somers 84*8aa24ed3SAlan Somers class Flock: public Locks { 85*8aa24ed3SAlan Somers public: 86*8aa24ed3SAlan Somers void expect_setlk(uint64_t ino, uint32_t type, int err) 87*8aa24ed3SAlan Somers { 88*8aa24ed3SAlan Somers EXPECT_CALL(*m_mock, process( 89*8aa24ed3SAlan Somers ResultOf([=](auto in) { 90*8aa24ed3SAlan Somers return (in.header.opcode == FUSE_SETLK && 91*8aa24ed3SAlan Somers in.header.nodeid == ino && 92*8aa24ed3SAlan Somers in.body.setlk.fh == FH && 93*8aa24ed3SAlan Somers /* 94*8aa24ed3SAlan Somers * The owner should be set to the address of 95*8aa24ed3SAlan Somers * the vnode. That's hard to verify. 96*8aa24ed3SAlan Somers */ 97*8aa24ed3SAlan Somers /* in.body.setlk.owner == ??? && */ 98*8aa24ed3SAlan Somers in.body.setlk.lk.type == type); 99*8aa24ed3SAlan Somers }, Eq(true)), 100*8aa24ed3SAlan Somers _) 101*8aa24ed3SAlan Somers ).WillOnce(Invoke(ReturnErrno(err))); 102*8aa24ed3SAlan Somers } 103*8aa24ed3SAlan Somers }; 104*8aa24ed3SAlan Somers 105*8aa24ed3SAlan Somers class FlockFallback: public Fallback {}; 1069821f1d3SAlan Somers class GetlkFallback: public Fallback {}; 107*8aa24ed3SAlan Somers class Getlk: public Fcntl {}; 1089821f1d3SAlan Somers class SetlkFallback: public Fallback {}; 109*8aa24ed3SAlan Somers class Setlk: public Fcntl {}; 1109821f1d3SAlan Somers class SetlkwFallback: public Fallback {}; 111*8aa24ed3SAlan Somers class Setlkw: public Fcntl {}; 112*8aa24ed3SAlan Somers 113*8aa24ed3SAlan Somers /* 114*8aa24ed3SAlan Somers * If the fuse filesystem does not support flock locks, then the kernel should 115*8aa24ed3SAlan Somers * fall back to local locks. 116*8aa24ed3SAlan Somers */ 117*8aa24ed3SAlan Somers TEST_F(FlockFallback, local) 118*8aa24ed3SAlan Somers { 119*8aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 120*8aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 121*8aa24ed3SAlan Somers uint64_t ino = 42; 122*8aa24ed3SAlan Somers int fd; 123*8aa24ed3SAlan Somers 124*8aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 125*8aa24ed3SAlan Somers expect_open(ino, 0, 1); 126*8aa24ed3SAlan Somers 127*8aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 128*8aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 129*8aa24ed3SAlan Somers ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno); 130*8aa24ed3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 131*8aa24ed3SAlan Somers } 132*8aa24ed3SAlan Somers 133*8aa24ed3SAlan Somers /* 134*8aa24ed3SAlan Somers * Even if the fuse file system supports POSIX locks, we must implement flock 135*8aa24ed3SAlan Somers * locks locally until protocol 7.17. Protocol 7.9 added partial buggy support 136*8aa24ed3SAlan Somers * but we won't implement that. 137*8aa24ed3SAlan Somers */ 138*8aa24ed3SAlan Somers TEST_F(Flock, local) 139*8aa24ed3SAlan Somers { 140*8aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 141*8aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 142*8aa24ed3SAlan Somers uint64_t ino = 42; 143*8aa24ed3SAlan Somers int fd; 144*8aa24ed3SAlan Somers 145*8aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 146*8aa24ed3SAlan Somers expect_open(ino, 0, 1); 147*8aa24ed3SAlan Somers 148*8aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 149*8aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 150*8aa24ed3SAlan Somers ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno); 151*8aa24ed3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 152*8aa24ed3SAlan Somers } 153*8aa24ed3SAlan Somers 154*8aa24ed3SAlan Somers /* Set a new flock lock with FUSE_SETLK */ 155*8aa24ed3SAlan Somers /* TODO: enable after upgrading to protocol 7.17 */ 156*8aa24ed3SAlan Somers TEST_F(Flock, DISABLED_set) 157*8aa24ed3SAlan Somers { 158*8aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 159*8aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 160*8aa24ed3SAlan Somers uint64_t ino = 42; 161*8aa24ed3SAlan Somers int fd; 162*8aa24ed3SAlan Somers 163*8aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 164*8aa24ed3SAlan Somers expect_open(ino, 0, 1); 165*8aa24ed3SAlan Somers expect_setlk(ino, F_WRLCK, 0); 166*8aa24ed3SAlan Somers 167*8aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 168*8aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 169*8aa24ed3SAlan Somers ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno); 170*8aa24ed3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 171*8aa24ed3SAlan Somers } 172*8aa24ed3SAlan Somers 173*8aa24ed3SAlan Somers /* Fail to set a flock lock in non-blocking mode */ 174*8aa24ed3SAlan Somers /* TODO: enable after upgrading to protocol 7.17 */ 175*8aa24ed3SAlan Somers TEST_F(Flock, DISABLED_eagain) 176*8aa24ed3SAlan Somers { 177*8aa24ed3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 178*8aa24ed3SAlan Somers const char RELPATH[] = "some_file.txt"; 179*8aa24ed3SAlan Somers uint64_t ino = 42; 180*8aa24ed3SAlan Somers int fd; 181*8aa24ed3SAlan Somers 182*8aa24ed3SAlan Somers expect_lookup(RELPATH, ino); 183*8aa24ed3SAlan Somers expect_open(ino, 0, 1); 184*8aa24ed3SAlan Somers expect_setlk(ino, F_WRLCK, EAGAIN); 185*8aa24ed3SAlan Somers 186*8aa24ed3SAlan Somers fd = open(FULLPATH, O_RDWR); 187*8aa24ed3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 188*8aa24ed3SAlan Somers ASSERT_NE(0, flock(fd, LOCK_EX | LOCK_NB)); 189*8aa24ed3SAlan Somers ASSERT_EQ(EAGAIN, errno); 190*8aa24ed3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 191*8aa24ed3SAlan Somers } 1929821f1d3SAlan Somers 1939821f1d3SAlan Somers /* 1949821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 1959821f1d3SAlan Somers * should fall back to local locks. 1969821f1d3SAlan Somers */ 1979821f1d3SAlan Somers TEST_F(GetlkFallback, local) 1989821f1d3SAlan Somers { 1999821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2009821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2019821f1d3SAlan Somers uint64_t ino = 42; 2029821f1d3SAlan Somers struct flock fl; 2039821f1d3SAlan Somers int fd; 2049821f1d3SAlan Somers 2059821f1d3SAlan Somers expect_lookup(RELPATH, ino); 2069821f1d3SAlan Somers expect_open(ino, 0, 1); 2079821f1d3SAlan Somers 2089821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 2099821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 2109821f1d3SAlan Somers fl.l_start = 10; 2119821f1d3SAlan Somers fl.l_len = 1000; 2129821f1d3SAlan Somers fl.l_pid = getpid(); 2139821f1d3SAlan Somers fl.l_type = F_RDLCK; 2149821f1d3SAlan Somers fl.l_whence = SEEK_SET; 2159821f1d3SAlan Somers fl.l_sysid = 0; 2169821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 2179821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 2189821f1d3SAlan Somers } 2199821f1d3SAlan Somers 2209821f1d3SAlan Somers /* 2219821f1d3SAlan Somers * If the filesystem has no locks that fit the description, the filesystem 2229821f1d3SAlan Somers * should return F_UNLCK 2239821f1d3SAlan Somers */ 224f067b609SAlan Somers TEST_F(Getlk, no_locks) 2259821f1d3SAlan Somers { 2269821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2279821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2289821f1d3SAlan Somers uint64_t ino = 42; 2299821f1d3SAlan Somers struct flock fl; 2309821f1d3SAlan Somers int fd; 2319821f1d3SAlan Somers pid_t pid = 1234; 2329821f1d3SAlan Somers 2339821f1d3SAlan Somers expect_lookup(RELPATH, ino); 2349821f1d3SAlan Somers expect_open(ino, 0, 1); 2359821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 2369821f1d3SAlan Somers ResultOf([=](auto in) { 23729edc611SAlan Somers return (in.header.opcode == FUSE_GETLK && 23829edc611SAlan Somers in.header.nodeid == ino && 23929edc611SAlan Somers in.body.getlk.fh == FH && 24029edc611SAlan Somers in.body.getlk.owner == (uint32_t)pid && 24129edc611SAlan Somers in.body.getlk.lk.start == 10 && 24229edc611SAlan Somers in.body.getlk.lk.end == 1009 && 24329edc611SAlan Somers in.body.getlk.lk.type == F_RDLCK && 24429edc611SAlan Somers in.body.getlk.lk.pid == (uint64_t)pid); 2459821f1d3SAlan Somers }, Eq(true)), 2469821f1d3SAlan Somers _) 24729edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) { 2489821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, getlk); 24929edc611SAlan Somers out.body.getlk.lk = in.body.getlk.lk; 25029edc611SAlan Somers out.body.getlk.lk.type = F_UNLCK; 2519821f1d3SAlan Somers }))); 2529821f1d3SAlan Somers 2539821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 2549821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 2559821f1d3SAlan Somers fl.l_start = 10; 2569821f1d3SAlan Somers fl.l_len = 1000; 2579821f1d3SAlan Somers fl.l_pid = pid; 2589821f1d3SAlan Somers fl.l_type = F_RDLCK; 2599821f1d3SAlan Somers fl.l_whence = SEEK_SET; 2609821f1d3SAlan Somers fl.l_sysid = 0; 2619821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 2629821f1d3SAlan Somers ASSERT_EQ(F_UNLCK, fl.l_type); 2639821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 2649821f1d3SAlan Somers } 2659821f1d3SAlan Somers 2669821f1d3SAlan Somers /* A different pid does have a lock */ 267f067b609SAlan Somers TEST_F(Getlk, lock_exists) 2689821f1d3SAlan Somers { 2699821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 2709821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 2719821f1d3SAlan Somers uint64_t ino = 42; 2729821f1d3SAlan Somers struct flock fl; 2739821f1d3SAlan Somers int fd; 2749821f1d3SAlan Somers pid_t pid = 1234; 2759821f1d3SAlan Somers pid_t pid2 = 1235; 2769821f1d3SAlan Somers 2779821f1d3SAlan Somers expect_lookup(RELPATH, ino); 2789821f1d3SAlan Somers expect_open(ino, 0, 1); 2799821f1d3SAlan Somers EXPECT_CALL(*m_mock, process( 2809821f1d3SAlan Somers ResultOf([=](auto in) { 28129edc611SAlan Somers return (in.header.opcode == FUSE_GETLK && 28229edc611SAlan Somers in.header.nodeid == ino && 28329edc611SAlan Somers in.body.getlk.fh == FH && 28429edc611SAlan Somers in.body.getlk.owner == (uint32_t)pid && 28529edc611SAlan Somers in.body.getlk.lk.start == 10 && 28629edc611SAlan Somers in.body.getlk.lk.end == 1009 && 28729edc611SAlan Somers in.body.getlk.lk.type == F_RDLCK && 28829edc611SAlan Somers in.body.getlk.lk.pid == (uint64_t)pid); 2899821f1d3SAlan Somers }, Eq(true)), 2909821f1d3SAlan Somers _) 29129edc611SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { 2929821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, getlk); 29329edc611SAlan Somers out.body.getlk.lk.start = 100; 29429edc611SAlan Somers out.body.getlk.lk.end = 199; 29529edc611SAlan Somers out.body.getlk.lk.type = F_WRLCK; 29629edc611SAlan Somers out.body.getlk.lk.pid = (uint32_t)pid2;; 2979821f1d3SAlan Somers }))); 2989821f1d3SAlan Somers 2999821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3009821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3019821f1d3SAlan Somers fl.l_start = 10; 3029821f1d3SAlan Somers fl.l_len = 1000; 3039821f1d3SAlan Somers fl.l_pid = pid; 3049821f1d3SAlan Somers fl.l_type = F_RDLCK; 3059821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3069821f1d3SAlan Somers fl.l_sysid = 0; 3079821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno); 3089821f1d3SAlan Somers EXPECT_EQ(100, fl.l_start); 3099821f1d3SAlan Somers EXPECT_EQ(100, fl.l_len); 3109821f1d3SAlan Somers EXPECT_EQ(pid2, fl.l_pid); 3119821f1d3SAlan Somers EXPECT_EQ(F_WRLCK, fl.l_type); 3129821f1d3SAlan Somers EXPECT_EQ(SEEK_SET, fl.l_whence); 3139821f1d3SAlan Somers EXPECT_EQ(0, fl.l_sysid); 3149821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 3159821f1d3SAlan Somers } 3169821f1d3SAlan Somers 3179821f1d3SAlan Somers /* 3189821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 3199821f1d3SAlan Somers * should fall back to local locks. 3209821f1d3SAlan Somers */ 3219821f1d3SAlan Somers TEST_F(SetlkFallback, local) 3229821f1d3SAlan Somers { 3239821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 3249821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 3259821f1d3SAlan Somers uint64_t ino = 42; 3269821f1d3SAlan Somers struct flock fl; 3279821f1d3SAlan Somers int fd; 3289821f1d3SAlan Somers 3299821f1d3SAlan Somers expect_lookup(RELPATH, ino); 3309821f1d3SAlan Somers expect_open(ino, 0, 1); 3319821f1d3SAlan Somers 3329821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3339821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3349821f1d3SAlan Somers fl.l_start = 10; 3359821f1d3SAlan Somers fl.l_len = 1000; 3369821f1d3SAlan Somers fl.l_pid = getpid(); 3379821f1d3SAlan Somers fl.l_type = F_RDLCK; 3389821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3399821f1d3SAlan Somers fl.l_sysid = 0; 3409821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 3419821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 3429821f1d3SAlan Somers } 3439821f1d3SAlan Somers 3449821f1d3SAlan Somers /* Set a new lock with FUSE_SETLK */ 345f067b609SAlan Somers TEST_F(Setlk, set) 3469821f1d3SAlan Somers { 3479821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 3489821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 3499821f1d3SAlan Somers uint64_t ino = 42; 3509821f1d3SAlan Somers struct flock fl; 3519821f1d3SAlan Somers int fd; 3529821f1d3SAlan Somers pid_t pid = 1234; 3539821f1d3SAlan Somers 3549821f1d3SAlan Somers expect_lookup(RELPATH, ino); 3559821f1d3SAlan Somers expect_open(ino, 0, 1); 356*8aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, 0); 3579821f1d3SAlan Somers 3589821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3599821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3609821f1d3SAlan Somers fl.l_start = 10; 3619821f1d3SAlan Somers fl.l_len = 1000; 3629821f1d3SAlan Somers fl.l_pid = pid; 3639821f1d3SAlan Somers fl.l_type = F_RDLCK; 3649821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3659821f1d3SAlan Somers fl.l_sysid = 0; 3669821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 3679821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 3689821f1d3SAlan Somers } 3699821f1d3SAlan Somers 3709821f1d3SAlan Somers /* l_len = 0 is a flag value that means to lock until EOF */ 371f067b609SAlan Somers TEST_F(Setlk, set_eof) 3729821f1d3SAlan Somers { 3739821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 3749821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 3759821f1d3SAlan Somers uint64_t ino = 42; 3769821f1d3SAlan Somers struct flock fl; 3779821f1d3SAlan Somers int fd; 3789821f1d3SAlan Somers pid_t pid = 1234; 3799821f1d3SAlan Somers 3809821f1d3SAlan Somers expect_lookup(RELPATH, ino); 3819821f1d3SAlan Somers expect_open(ino, 0, 1); 382*8aa24ed3SAlan Somers expect_setlk(ino, pid, 10, OFFSET_MAX, F_RDLCK, 0); 3839821f1d3SAlan Somers 3849821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 3859821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 3869821f1d3SAlan Somers fl.l_start = 10; 3879821f1d3SAlan Somers fl.l_len = 0; 3889821f1d3SAlan Somers fl.l_pid = pid; 3899821f1d3SAlan Somers fl.l_type = F_RDLCK; 3909821f1d3SAlan Somers fl.l_whence = SEEK_SET; 3919821f1d3SAlan Somers fl.l_sysid = 0; 3929821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno); 3939821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 3949821f1d3SAlan Somers } 3959821f1d3SAlan Somers 3969821f1d3SAlan Somers /* Fail to set a new lock with FUSE_SETLK due to a conflict */ 397f067b609SAlan Somers TEST_F(Setlk, eagain) 3989821f1d3SAlan Somers { 3999821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4009821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4019821f1d3SAlan Somers uint64_t ino = 42; 4029821f1d3SAlan Somers struct flock fl; 4039821f1d3SAlan Somers int fd; 4049821f1d3SAlan Somers pid_t pid = 1234; 4059821f1d3SAlan Somers 4069821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4079821f1d3SAlan Somers expect_open(ino, 0, 1); 408*8aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, EAGAIN); 4099821f1d3SAlan Somers 4109821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4119821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4129821f1d3SAlan Somers fl.l_start = 10; 4139821f1d3SAlan Somers fl.l_len = 1000; 4149821f1d3SAlan Somers fl.l_pid = pid; 4159821f1d3SAlan Somers fl.l_type = F_RDLCK; 4169821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4179821f1d3SAlan Somers fl.l_sysid = 0; 4189821f1d3SAlan Somers ASSERT_EQ(-1, fcntl(fd, F_SETLK, &fl)); 4199821f1d3SAlan Somers ASSERT_EQ(EAGAIN, errno); 4209821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 4219821f1d3SAlan Somers } 4229821f1d3SAlan Somers 4239821f1d3SAlan Somers /* 4249821f1d3SAlan Somers * If the fuse filesystem does not support posix file locks, then the kernel 4259821f1d3SAlan Somers * should fall back to local locks. 4269821f1d3SAlan Somers */ 4279821f1d3SAlan Somers TEST_F(SetlkwFallback, local) 4289821f1d3SAlan Somers { 4299821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4309821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4319821f1d3SAlan Somers uint64_t ino = 42; 4329821f1d3SAlan Somers struct flock fl; 4339821f1d3SAlan Somers int fd; 4349821f1d3SAlan Somers 4359821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4369821f1d3SAlan Somers expect_open(ino, 0, 1); 4379821f1d3SAlan Somers 4389821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4399821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4409821f1d3SAlan Somers fl.l_start = 10; 4419821f1d3SAlan Somers fl.l_len = 1000; 4429821f1d3SAlan Somers fl.l_pid = getpid(); 4439821f1d3SAlan Somers fl.l_type = F_RDLCK; 4449821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4459821f1d3SAlan Somers fl.l_sysid = 0; 4469821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno); 4479821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 4489821f1d3SAlan Somers } 4499821f1d3SAlan Somers 4509821f1d3SAlan Somers /* 4519821f1d3SAlan Somers * Set a new lock with FUSE_SETLK. If the lock is not available, then the 4529821f1d3SAlan Somers * command should block. But to the kernel, that's the same as just being 4539821f1d3SAlan Somers * slow, so we don't need a separate test method 4549821f1d3SAlan Somers */ 455f067b609SAlan Somers TEST_F(Setlkw, set) 4569821f1d3SAlan Somers { 4579821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_file.txt"; 4589821f1d3SAlan Somers const char RELPATH[] = "some_file.txt"; 4599821f1d3SAlan Somers uint64_t ino = 42; 4609821f1d3SAlan Somers struct flock fl; 4619821f1d3SAlan Somers int fd; 4629821f1d3SAlan Somers pid_t pid = 1234; 4639821f1d3SAlan Somers 4649821f1d3SAlan Somers expect_lookup(RELPATH, ino); 4659821f1d3SAlan Somers expect_open(ino, 0, 1); 466*8aa24ed3SAlan Somers expect_setlk(ino, pid, 10, 1009, F_RDLCK, 0); 4679821f1d3SAlan Somers 4689821f1d3SAlan Somers fd = open(FULLPATH, O_RDWR); 4699821f1d3SAlan Somers ASSERT_LE(0, fd) << strerror(errno); 4709821f1d3SAlan Somers fl.l_start = 10; 4719821f1d3SAlan Somers fl.l_len = 1000; 4729821f1d3SAlan Somers fl.l_pid = pid; 4739821f1d3SAlan Somers fl.l_type = F_RDLCK; 4749821f1d3SAlan Somers fl.l_whence = SEEK_SET; 4759821f1d3SAlan Somers fl.l_sysid = 0; 4769821f1d3SAlan Somers ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno); 4779821f1d3SAlan Somers /* Deliberately leak fd. close(2) will be tested in release.cc */ 4789821f1d3SAlan Somers } 479