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