Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/fs/fusefs/locks.cc
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 The FreeBSD Foundation
5
*
6
* This software was developed by BFF Storage Systems, LLC under sponsorship
7
* from the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
extern "C" {
32
#include <sys/file.h>
33
#include <fcntl.h>
34
}
35
36
#include "mockfs.hh"
37
#include "utils.hh"
38
39
/* This flag value should probably be defined in fuse_kernel.h */
40
#define OFFSET_MAX 0x7fffffffffffffffLL
41
42
using namespace testing;
43
44
/* For testing filesystems without posix locking support */
45
class Fallback: public FuseTest {
46
public:
47
48
void expect_lookup(const char *relpath, uint64_t ino, uint64_t size = 0)
49
{
50
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, size, 1);
51
}
52
53
};
54
55
/* For testing filesystems with posix locking support */
56
class Locks: public Fallback {
57
virtual void SetUp() {
58
m_init_flags = FUSE_POSIX_LOCKS;
59
Fallback::SetUp();
60
}
61
};
62
63
class Fcntl: public Locks {
64
public:
65
void expect_setlk(uint64_t ino, pid_t pid, uint64_t start, uint64_t end,
66
uint32_t type, int err)
67
{
68
EXPECT_CALL(*m_mock, process(
69
ResultOf([=](auto in) {
70
return (in.header.opcode == FUSE_SETLK &&
71
in.header.nodeid == ino &&
72
in.body.setlk.fh == FH &&
73
in.body.setlk.owner == (uint32_t)pid &&
74
in.body.setlk.lk.start == start &&
75
in.body.setlk.lk.end == end &&
76
in.body.setlk.lk.type == type &&
77
in.body.setlk.lk.pid == (uint64_t)pid);
78
}, Eq(true)),
79
_)
80
).WillOnce(Invoke(ReturnErrno(err)));
81
}
82
void expect_setlkw(uint64_t ino, pid_t pid, uint64_t start, uint64_t end,
83
uint32_t type, int err)
84
{
85
EXPECT_CALL(*m_mock, process(
86
ResultOf([=](auto in) {
87
return (in.header.opcode == FUSE_SETLKW &&
88
in.header.nodeid == ino &&
89
in.body.setlkw.fh == FH &&
90
in.body.setlkw.owner == (uint32_t)pid &&
91
in.body.setlkw.lk.start == start &&
92
in.body.setlkw.lk.end == end &&
93
in.body.setlkw.lk.type == type &&
94
in.body.setlkw.lk.pid == (uint64_t)pid);
95
}, Eq(true)),
96
_)
97
).WillOnce(Invoke(ReturnErrno(err)));
98
}
99
};
100
101
class Flock: public Locks {
102
public:
103
void expect_setlk(uint64_t ino, uint32_t type, int err)
104
{
105
EXPECT_CALL(*m_mock, process(
106
ResultOf([=](auto in) {
107
return (in.header.opcode == FUSE_SETLK &&
108
in.header.nodeid == ino &&
109
in.body.setlk.fh == FH &&
110
/*
111
* The owner should be set to the address of
112
* the vnode. That's hard to verify.
113
*/
114
/* in.body.setlk.owner == ??? && */
115
in.body.setlk.lk.type == type);
116
}, Eq(true)),
117
_)
118
).WillOnce(Invoke(ReturnErrno(err)));
119
}
120
};
121
122
class FlockFallback: public Fallback {};
123
class GetlkFallback: public Fallback {};
124
class Getlk: public Fcntl {};
125
class SetlkFallback: public Fallback {};
126
class Setlk: public Fcntl {};
127
class SetlkwFallback: public Fallback {};
128
class Setlkw: public Fcntl {};
129
130
/*
131
* If the fuse filesystem does not support flock locks, then the kernel should
132
* fall back to local locks.
133
*/
134
TEST_F(FlockFallback, local)
135
{
136
const char FULLPATH[] = "mountpoint/some_file.txt";
137
const char RELPATH[] = "some_file.txt";
138
uint64_t ino = 42;
139
int fd;
140
141
expect_lookup(RELPATH, ino);
142
expect_open(ino, 0, 1);
143
144
fd = open(FULLPATH, O_RDWR);
145
ASSERT_LE(0, fd) << strerror(errno);
146
ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno);
147
leak(fd);
148
}
149
150
/*
151
* Even if the fuse file system supports POSIX locks, we must implement flock
152
* locks locally until protocol 7.17. Protocol 7.9 added partial buggy support
153
* but we won't implement that.
154
*/
155
TEST_F(Flock, local)
156
{
157
const char FULLPATH[] = "mountpoint/some_file.txt";
158
const char RELPATH[] = "some_file.txt";
159
uint64_t ino = 42;
160
int fd;
161
162
expect_lookup(RELPATH, ino);
163
expect_open(ino, 0, 1);
164
165
fd = open(FULLPATH, O_RDWR);
166
ASSERT_LE(0, fd) << strerror(errno);
167
ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno);
168
leak(fd);
169
}
170
171
/* Set a new flock lock with FUSE_SETLK */
172
/* TODO: enable after upgrading to protocol 7.17 */
173
TEST_F(Flock, DISABLED_set)
174
{
175
const char FULLPATH[] = "mountpoint/some_file.txt";
176
const char RELPATH[] = "some_file.txt";
177
uint64_t ino = 42;
178
int fd;
179
180
expect_lookup(RELPATH, ino);
181
expect_open(ino, 0, 1);
182
expect_setlk(ino, F_WRLCK, 0);
183
184
fd = open(FULLPATH, O_RDWR);
185
ASSERT_LE(0, fd) << strerror(errno);
186
ASSERT_EQ(0, flock(fd, LOCK_EX)) << strerror(errno);
187
leak(fd);
188
}
189
190
/* Fail to set a flock lock in non-blocking mode */
191
/* TODO: enable after upgrading to protocol 7.17 */
192
TEST_F(Flock, DISABLED_eagain)
193
{
194
const char FULLPATH[] = "mountpoint/some_file.txt";
195
const char RELPATH[] = "some_file.txt";
196
uint64_t ino = 42;
197
int fd;
198
199
expect_lookup(RELPATH, ino);
200
expect_open(ino, 0, 1);
201
expect_setlk(ino, F_WRLCK, EAGAIN);
202
203
fd = open(FULLPATH, O_RDWR);
204
ASSERT_LE(0, fd) << strerror(errno);
205
ASSERT_NE(0, flock(fd, LOCK_EX | LOCK_NB));
206
ASSERT_EQ(EAGAIN, errno);
207
leak(fd);
208
}
209
210
/*
211
* If the fuse filesystem does not support posix file locks, then the kernel
212
* should fall back to local locks.
213
*/
214
TEST_F(GetlkFallback, local)
215
{
216
const char FULLPATH[] = "mountpoint/some_file.txt";
217
const char RELPATH[] = "some_file.txt";
218
uint64_t ino = 42;
219
struct flock fl;
220
int fd;
221
222
expect_lookup(RELPATH, ino);
223
expect_open(ino, 0, 1);
224
225
fd = open(FULLPATH, O_RDWR);
226
ASSERT_LE(0, fd) << strerror(errno);
227
fl.l_start = 10;
228
fl.l_len = 1000;
229
fl.l_pid = 0;
230
fl.l_type = F_RDLCK;
231
fl.l_whence = SEEK_SET;
232
fl.l_sysid = 0;
233
ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno);
234
leak(fd);
235
}
236
237
/*
238
* If the filesystem has no locks that fit the description, the filesystem
239
* should return F_UNLCK
240
*/
241
TEST_F(Getlk, no_locks)
242
{
243
const char FULLPATH[] = "mountpoint/some_file.txt";
244
const char RELPATH[] = "some_file.txt";
245
uint64_t ino = 42;
246
struct flock fl;
247
int fd;
248
pid_t pid = getpid();
249
250
expect_lookup(RELPATH, ino);
251
expect_open(ino, 0, 1);
252
EXPECT_CALL(*m_mock, process(
253
ResultOf([=](auto in) {
254
return (in.header.opcode == FUSE_GETLK &&
255
in.header.nodeid == ino &&
256
in.body.getlk.fh == FH &&
257
/*
258
* Though it seems useless, libfuse expects the
259
* owner and pid fields to be set during
260
* FUSE_GETLK.
261
*/
262
in.body.getlk.owner == (uint32_t)pid &&
263
in.body.getlk.lk.pid == (uint64_t)pid &&
264
in.body.getlk.lk.start == 10 &&
265
in.body.getlk.lk.end == 1009 &&
266
in.body.getlk.lk.type == F_RDLCK);
267
}, Eq(true)),
268
_)
269
).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) {
270
SET_OUT_HEADER_LEN(out, getlk);
271
out.body.getlk.lk = in.body.getlk.lk;
272
out.body.getlk.lk.type = F_UNLCK;
273
})));
274
275
fd = open(FULLPATH, O_RDWR);
276
ASSERT_LE(0, fd) << strerror(errno);
277
fl.l_start = 10;
278
fl.l_len = 1000;
279
fl.l_pid = 42;
280
fl.l_type = F_RDLCK;
281
fl.l_whence = SEEK_SET;
282
fl.l_sysid = 42;
283
ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno);
284
285
/*
286
* If no lock is found that would prevent this lock from being created,
287
* the structure is left unchanged by this system call except for the
288
* lock type which is set to F_UNLCK.
289
*/
290
ASSERT_EQ(F_UNLCK, fl.l_type);
291
ASSERT_EQ(fl.l_pid, 42);
292
ASSERT_EQ(fl.l_start, 10);
293
ASSERT_EQ(fl.l_len, 1000);
294
ASSERT_EQ(fl.l_whence, SEEK_SET);
295
ASSERT_EQ(fl.l_sysid, 42);
296
297
leak(fd);
298
}
299
300
/* A different pid does have a lock */
301
TEST_F(Getlk, lock_exists)
302
{
303
const char FULLPATH[] = "mountpoint/some_file.txt";
304
const char RELPATH[] = "some_file.txt";
305
uint64_t ino = 42;
306
struct flock fl;
307
int fd;
308
pid_t pid = getpid();
309
pid_t pid2 = 1235;
310
311
expect_lookup(RELPATH, ino);
312
expect_open(ino, 0, 1);
313
EXPECT_CALL(*m_mock, process(
314
ResultOf([=](auto in) {
315
return (in.header.opcode == FUSE_GETLK &&
316
in.header.nodeid == ino &&
317
in.body.getlk.fh == FH &&
318
/*
319
* Though it seems useless, libfuse expects the
320
* owner and pid fields to be set during
321
* FUSE_GETLK.
322
*/
323
in.body.getlk.owner == (uint32_t)pid &&
324
in.body.getlk.lk.pid == (uint64_t)pid &&
325
in.body.getlk.lk.start == 10 &&
326
in.body.getlk.lk.end == 1009 &&
327
in.body.getlk.lk.type == F_RDLCK);
328
}, Eq(true)),
329
_)
330
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
331
SET_OUT_HEADER_LEN(out, getlk);
332
out.body.getlk.lk.start = 100;
333
out.body.getlk.lk.end = 199;
334
out.body.getlk.lk.type = F_WRLCK;
335
out.body.getlk.lk.pid = (uint32_t)pid2;;
336
})));
337
338
fd = open(FULLPATH, O_RDWR);
339
ASSERT_LE(0, fd) << strerror(errno);
340
fl.l_start = 10;
341
fl.l_len = 1000;
342
fl.l_pid = 0;
343
fl.l_type = F_RDLCK;
344
fl.l_whence = SEEK_SET;
345
fl.l_sysid = 0;
346
ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno);
347
EXPECT_EQ(100, fl.l_start);
348
EXPECT_EQ(100, fl.l_len);
349
EXPECT_EQ(pid2, fl.l_pid);
350
EXPECT_EQ(F_WRLCK, fl.l_type);
351
EXPECT_EQ(SEEK_SET, fl.l_whence);
352
EXPECT_EQ(0, fl.l_sysid);
353
leak(fd);
354
}
355
356
/*
357
* F_GETLK with SEEK_CUR
358
*/
359
TEST_F(Getlk, seek_cur)
360
{
361
const char FULLPATH[] = "mountpoint/some_file.txt";
362
const char RELPATH[] = "some_file.txt";
363
uint64_t ino = 42;
364
struct flock fl;
365
int fd;
366
pid_t pid = getpid();
367
368
expect_lookup(RELPATH, ino, 1024);
369
expect_open(ino, 0, 1);
370
EXPECT_CALL(*m_mock, process(
371
ResultOf([=](auto in) {
372
return (in.header.opcode == FUSE_GETLK &&
373
in.header.nodeid == ino &&
374
in.body.getlk.fh == FH &&
375
/*
376
* Though it seems useless, libfuse expects the
377
* owner and pid fields to be set during
378
* FUSE_GETLK.
379
*/
380
in.body.getlk.owner == (uint32_t)pid &&
381
in.body.getlk.lk.pid == (uint64_t)pid &&
382
in.body.getlk.lk.start == 500 &&
383
in.body.getlk.lk.end == 509 &&
384
in.body.getlk.lk.type == F_RDLCK);
385
}, Eq(true)),
386
_)
387
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
388
SET_OUT_HEADER_LEN(out, getlk);
389
out.body.getlk.lk.start = 400;
390
out.body.getlk.lk.end = 499;
391
out.body.getlk.lk.type = F_WRLCK;
392
out.body.getlk.lk.pid = (uint32_t)pid + 1;
393
})));
394
395
fd = open(FULLPATH, O_RDWR);
396
ASSERT_LE(0, fd) << strerror(errno);
397
ASSERT_NE(-1, lseek(fd, 500, SEEK_SET));
398
399
fl.l_start = 0;
400
fl.l_len = 10;
401
fl.l_pid = 42;
402
fl.l_type = F_RDLCK;
403
fl.l_whence = SEEK_CUR;
404
fl.l_sysid = 0;
405
ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno);
406
407
/*
408
* After a successful F_GETLK request, the value of l_whence is
409
* SEEK_SET.
410
*/
411
EXPECT_EQ(F_WRLCK, fl.l_type);
412
EXPECT_EQ(fl.l_pid, pid + 1);
413
EXPECT_EQ(fl.l_start, 400);
414
EXPECT_EQ(fl.l_len, 100);
415
EXPECT_EQ(fl.l_whence, SEEK_SET);
416
ASSERT_EQ(fl.l_sysid, 0);
417
418
leak(fd);
419
}
420
421
/*
422
* F_GETLK with SEEK_END
423
*/
424
TEST_F(Getlk, seek_end)
425
{
426
const char FULLPATH[] = "mountpoint/some_file.txt";
427
const char RELPATH[] = "some_file.txt";
428
uint64_t ino = 42;
429
struct flock fl;
430
int fd;
431
pid_t pid = getpid();
432
433
expect_lookup(RELPATH, ino, 1024);
434
expect_open(ino, 0, 1);
435
EXPECT_CALL(*m_mock, process(
436
ResultOf([=](auto in) {
437
return (in.header.opcode == FUSE_GETLK &&
438
in.header.nodeid == ino &&
439
in.body.getlk.fh == FH &&
440
/*
441
* Though it seems useless, libfuse expects the
442
* owner and pid fields to be set during
443
* FUSE_GETLK.
444
*/
445
in.body.getlk.owner == (uint32_t)pid &&
446
in.body.getlk.lk.pid == (uint64_t)pid &&
447
in.body.getlk.lk.start == 512 &&
448
in.body.getlk.lk.end == 1023 &&
449
in.body.getlk.lk.type == F_RDLCK);
450
}, Eq(true)),
451
_)
452
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
453
SET_OUT_HEADER_LEN(out, getlk);
454
out.body.getlk.lk.start = 400;
455
out.body.getlk.lk.end = 499;
456
out.body.getlk.lk.type = F_WRLCK;
457
out.body.getlk.lk.pid = (uint32_t)pid + 1;
458
})));
459
460
fd = open(FULLPATH, O_RDWR);
461
ASSERT_LE(0, fd) << strerror(errno);
462
ASSERT_NE(-1, lseek(fd, 500, SEEK_SET));
463
464
fl.l_start = -512;
465
fl.l_len = 512;
466
fl.l_pid = 42;
467
fl.l_type = F_RDLCK;
468
fl.l_whence = SEEK_END;
469
fl.l_sysid = 0;
470
ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno);
471
472
/*
473
* After a successful F_GETLK request, the value of l_whence is
474
* SEEK_SET.
475
*/
476
EXPECT_EQ(F_WRLCK, fl.l_type);
477
EXPECT_EQ(fl.l_pid, pid + 1);
478
EXPECT_EQ(fl.l_start, 400);
479
EXPECT_EQ(fl.l_len, 100);
480
EXPECT_EQ(fl.l_whence, SEEK_SET);
481
ASSERT_EQ(fl.l_sysid, 0);
482
483
leak(fd);
484
}
485
486
/*
487
* If the fuse filesystem does not support posix file locks, then the kernel
488
* should fall back to local locks.
489
*/
490
TEST_F(SetlkFallback, local)
491
{
492
const char FULLPATH[] = "mountpoint/some_file.txt";
493
const char RELPATH[] = "some_file.txt";
494
uint64_t ino = 42;
495
struct flock fl;
496
int fd;
497
498
expect_lookup(RELPATH, ino);
499
expect_open(ino, 0, 1);
500
501
fd = open(FULLPATH, O_RDWR);
502
ASSERT_LE(0, fd) << strerror(errno);
503
fl.l_start = 10;
504
fl.l_len = 1000;
505
fl.l_pid = getpid();
506
fl.l_type = F_RDLCK;
507
fl.l_whence = SEEK_SET;
508
fl.l_sysid = 0;
509
ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
510
leak(fd);
511
}
512
513
/* Clear a lock with FUSE_SETLK */
514
TEST_F(Setlk, clear)
515
{
516
const char FULLPATH[] = "mountpoint/some_file.txt";
517
const char RELPATH[] = "some_file.txt";
518
uint64_t ino = 42;
519
struct flock fl;
520
int fd;
521
pid_t pid = getpid();
522
523
expect_lookup(RELPATH, ino);
524
expect_open(ino, 0, 1);
525
expect_setlk(ino, pid, 10, 1009, F_UNLCK, 0);
526
527
fd = open(FULLPATH, O_RDWR);
528
ASSERT_LE(0, fd) << strerror(errno);
529
fl.l_start = 10;
530
fl.l_len = 1000;
531
fl.l_pid = 0;
532
fl.l_type = F_UNLCK;
533
fl.l_whence = SEEK_SET;
534
fl.l_sysid = 0;
535
ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
536
leak(fd);
537
}
538
539
/* Set a new lock with FUSE_SETLK */
540
TEST_F(Setlk, set)
541
{
542
const char FULLPATH[] = "mountpoint/some_file.txt";
543
const char RELPATH[] = "some_file.txt";
544
uint64_t ino = 42;
545
struct flock fl;
546
int fd;
547
pid_t pid = getpid();
548
549
expect_lookup(RELPATH, ino);
550
expect_open(ino, 0, 1);
551
expect_setlk(ino, pid, 10, 1009, F_RDLCK, 0);
552
553
fd = open(FULLPATH, O_RDWR);
554
ASSERT_LE(0, fd) << strerror(errno);
555
fl.l_start = 10;
556
fl.l_len = 1000;
557
fl.l_pid = 0;
558
fl.l_type = F_RDLCK;
559
fl.l_whence = SEEK_SET;
560
fl.l_sysid = 0;
561
ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
562
leak(fd);
563
}
564
565
/* l_len = 0 is a flag value that means to lock until EOF */
566
TEST_F(Setlk, set_eof)
567
{
568
const char FULLPATH[] = "mountpoint/some_file.txt";
569
const char RELPATH[] = "some_file.txt";
570
uint64_t ino = 42;
571
struct flock fl;
572
int fd;
573
pid_t pid = getpid();
574
575
expect_lookup(RELPATH, ino);
576
expect_open(ino, 0, 1);
577
expect_setlk(ino, pid, 10, OFFSET_MAX, F_RDLCK, 0);
578
579
fd = open(FULLPATH, O_RDWR);
580
ASSERT_LE(0, fd) << strerror(errno);
581
fl.l_start = 10;
582
fl.l_len = 0;
583
fl.l_pid = 0;
584
fl.l_type = F_RDLCK;
585
fl.l_whence = SEEK_SET;
586
fl.l_sysid = 0;
587
ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
588
leak(fd);
589
}
590
591
/* Set a new lock with FUSE_SETLK, using SEEK_CUR for l_whence */
592
TEST_F(Setlk, set_seek_cur)
593
{
594
const char FULLPATH[] = "mountpoint/some_file.txt";
595
const char RELPATH[] = "some_file.txt";
596
uint64_t ino = 42;
597
struct flock fl;
598
int fd;
599
pid_t pid = getpid();
600
601
expect_lookup(RELPATH, ino, 1024);
602
expect_open(ino, 0, 1);
603
expect_setlk(ino, pid, 500, 509, F_RDLCK, 0);
604
605
fd = open(FULLPATH, O_RDWR);
606
ASSERT_LE(0, fd) << strerror(errno);
607
ASSERT_NE(-1, lseek(fd, 500, SEEK_SET));
608
609
fl.l_start = 0;
610
fl.l_len = 10;
611
fl.l_pid = 0;
612
fl.l_type = F_RDLCK;
613
fl.l_whence = SEEK_CUR;
614
fl.l_sysid = 0;
615
ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
616
617
leak(fd);
618
}
619
620
/* Set a new lock with FUSE_SETLK, using SEEK_END for l_whence */
621
TEST_F(Setlk, set_seek_end)
622
{
623
const char FULLPATH[] = "mountpoint/some_file.txt";
624
const char RELPATH[] = "some_file.txt";
625
uint64_t ino = 42;
626
struct flock fl;
627
int fd;
628
pid_t pid = getpid();
629
630
expect_lookup(RELPATH, ino, 1024);
631
expect_open(ino, 0, 1);
632
expect_setlk(ino, pid, 1000, 1009, F_RDLCK, 0);
633
634
fd = open(FULLPATH, O_RDWR);
635
ASSERT_LE(0, fd) << strerror(errno);
636
637
fl.l_start = -24;
638
fl.l_len = 10;
639
fl.l_pid = 0;
640
fl.l_type = F_RDLCK;
641
fl.l_whence = SEEK_END;
642
fl.l_sysid = 0;
643
ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
644
645
leak(fd);
646
}
647
648
/* Fail to set a new lock with FUSE_SETLK due to a conflict */
649
TEST_F(Setlk, eagain)
650
{
651
const char FULLPATH[] = "mountpoint/some_file.txt";
652
const char RELPATH[] = "some_file.txt";
653
uint64_t ino = 42;
654
struct flock fl;
655
int fd;
656
pid_t pid = getpid();
657
658
expect_lookup(RELPATH, ino);
659
expect_open(ino, 0, 1);
660
expect_setlk(ino, pid, 10, 1009, F_RDLCK, EAGAIN);
661
662
fd = open(FULLPATH, O_RDWR);
663
ASSERT_LE(0, fd) << strerror(errno);
664
fl.l_start = 10;
665
fl.l_len = 1000;
666
fl.l_pid = 0;
667
fl.l_type = F_RDLCK;
668
fl.l_whence = SEEK_SET;
669
fl.l_sysid = 0;
670
ASSERT_EQ(-1, fcntl(fd, F_SETLK, &fl));
671
ASSERT_EQ(EAGAIN, errno);
672
leak(fd);
673
}
674
675
/*
676
* If the fuse filesystem does not support posix file locks, then the kernel
677
* should fall back to local locks.
678
*/
679
TEST_F(SetlkwFallback, local)
680
{
681
const char FULLPATH[] = "mountpoint/some_file.txt";
682
const char RELPATH[] = "some_file.txt";
683
uint64_t ino = 42;
684
struct flock fl;
685
int fd;
686
687
expect_lookup(RELPATH, ino);
688
expect_open(ino, 0, 1);
689
690
fd = open(FULLPATH, O_RDWR);
691
ASSERT_LE(0, fd) << strerror(errno);
692
fl.l_start = 10;
693
fl.l_len = 1000;
694
fl.l_pid = 0;
695
fl.l_type = F_RDLCK;
696
fl.l_whence = SEEK_SET;
697
fl.l_sysid = 0;
698
ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno);
699
leak(fd);
700
}
701
702
/*
703
* Set a new lock with FUSE_SETLK. If the lock is not available, then the
704
* command should block. But to the kernel, that's the same as just being
705
* slow, so we don't need a separate test method
706
*/
707
TEST_F(Setlkw, set)
708
{
709
const char FULLPATH[] = "mountpoint/some_file.txt";
710
const char RELPATH[] = "some_file.txt";
711
uint64_t ino = 42;
712
struct flock fl;
713
int fd;
714
pid_t pid = getpid();
715
716
expect_lookup(RELPATH, ino);
717
expect_open(ino, 0, 1);
718
expect_setlkw(ino, pid, 10, 1009, F_RDLCK, 0);
719
720
fd = open(FULLPATH, O_RDWR);
721
ASSERT_LE(0, fd) << strerror(errno);
722
fl.l_start = 10;
723
fl.l_len = 1000;
724
fl.l_pid = 0;
725
fl.l_type = F_RDLCK;
726
fl.l_whence = SEEK_SET;
727
fl.l_sysid = 0;
728
ASSERT_NE(-1, fcntl(fd, F_SETLKW, &fl)) << strerror(errno);
729
leak(fd);
730
}
731
732