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