xref: /freebsd/tests/sys/fs/fusefs/locks.cc (revision 18b19f8c6e04935a63a951afe0e540674bc94455)
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