Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/file/flock_helper.c
39536 views
1
/*-
2
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3
* Authors: Doug Rabson <[email protected]>
4
* Developed with Red Inc: Alfred Perlstein <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/file.h>
30
#include <sys/time.h>
31
#ifdef __FreeBSD__
32
#include <sys/mount.h>
33
#endif
34
#include <sys/stat.h>
35
#include <sys/wait.h>
36
37
#include <err.h>
38
#include <errno.h>
39
#include <fcntl.h>
40
#include <pthread.h>
41
#include <signal.h>
42
#include <stdint.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <unistd.h>
47
48
#ifdef __FreeBSD__
49
#if __FreeBSD_version >= 800028
50
#define HAVE_SYSID
51
#endif
52
#include <sys/cdefs.h>
53
#else
54
#ifndef nitems
55
#define nitems(x) (sizeof((x)) / sizeof((x)[0]))
56
#endif
57
58
#ifndef __unused
59
#ifdef __GNUC__
60
#define __unused __attribute__((__unused__))
61
#else
62
#define __unused
63
#endif
64
#endif
65
#endif
66
67
static int verbose = 0;
68
69
static int
70
make_file(const char *pathname, off_t sz)
71
{
72
struct stat st;
73
const char *template = "/flocktempXXXXXX";
74
size_t len;
75
char *filename;
76
int fd;
77
78
if (stat(pathname, &st) == 0) {
79
if (S_ISREG(st.st_mode)) {
80
fd = open(pathname, O_RDWR);
81
if (fd < 0)
82
err(1, "open(%s)", pathname);
83
if (ftruncate(fd, sz) < 0)
84
err(1, "ftruncate");
85
return (fd);
86
}
87
}
88
89
len = strlen(pathname) + strlen(template) + 1;
90
filename = malloc(len);
91
strcpy(filename, pathname);
92
strcat(filename, template);
93
fd = mkstemp(filename);
94
if (fd < 0)
95
err(1, "mkstemp");
96
if (ftruncate(fd, sz) < 0)
97
err(1, "ftruncate");
98
if (unlink(filename) < 0)
99
err(1, "unlink");
100
free(filename);
101
102
return (fd);
103
}
104
105
static void
106
ignore_alarm(int __unused sig)
107
{
108
}
109
110
static int
111
safe_waitpid(pid_t pid)
112
{
113
int save_errno;
114
int status;
115
116
save_errno = errno;
117
errno = 0;
118
while (waitpid(pid, &status, 0) != pid) {
119
if (errno == EINTR)
120
continue;
121
err(1, "waitpid");
122
}
123
errno = save_errno;
124
125
return (status);
126
}
127
128
#define FAIL(test) \
129
do { \
130
if (test) { \
131
printf("FAIL (%s)\n", #test); \
132
return -1; \
133
} \
134
} while (0)
135
136
#define SUCCEED \
137
do { printf("SUCCEED\n"); return 0; } while (0)
138
139
/*
140
* Test 1 - F_GETLK on unlocked region
141
*
142
* If no lock is found that would prevent this lock from being
143
* created, the structure is left unchanged by this function call
144
* except for the lock type which is set to F_UNLCK.
145
*/
146
static int
147
test1(int fd, __unused int argc, const __unused char **argv)
148
{
149
struct flock fl1, fl2;
150
151
memset(&fl1, 1, sizeof(fl1));
152
fl1.l_type = F_WRLCK;
153
fl1.l_whence = SEEK_SET;
154
fl2 = fl1;
155
156
if (fcntl(fd, F_GETLK, &fl1) < 0)
157
err(1, "F_GETLK");
158
159
printf("1 - F_GETLK on unlocked region: ");
160
FAIL(fl1.l_start != fl2.l_start);
161
FAIL(fl1.l_len != fl2.l_len);
162
FAIL(fl1.l_pid != fl2.l_pid);
163
FAIL(fl1.l_type != F_UNLCK);
164
FAIL(fl1.l_whence != fl2.l_whence);
165
#ifdef HAVE_SYSID
166
FAIL(fl1.l_sysid != fl2.l_sysid);
167
#endif
168
169
SUCCEED;
170
}
171
172
/*
173
* Test 2 - F_SETLK on locked region
174
*
175
* If a shared or exclusive lock cannot be set, fcntl returns
176
* immediately with EACCES or EAGAIN.
177
*/
178
static int
179
test2(int fd, __unused int argc, const __unused char **argv)
180
{
181
/*
182
* We create a child process to hold the lock which we will
183
* test. We use a pipe to communicate with the child.
184
*/
185
int pid;
186
int pfd[2];
187
struct flock fl;
188
char ch;
189
int res;
190
191
if (pipe(pfd) < 0)
192
err(1, "pipe");
193
194
fl.l_start = 0;
195
fl.l_len = 0;
196
fl.l_type = F_WRLCK;
197
fl.l_whence = SEEK_SET;
198
199
pid = fork();
200
if (pid < 0)
201
err(1, "fork");
202
203
if (pid == 0) {
204
/*
205
* We are the child. We set a write lock and then
206
* write one byte back to the parent to tell it. The
207
* parent will kill us when its done.
208
*/
209
if (fcntl(fd, F_SETLK, &fl) < 0)
210
err(1, "F_SETLK (child)");
211
if (write(pfd[1], "a", 1) < 0)
212
err(1, "writing to pipe (child)");
213
pause();
214
exit(0);
215
}
216
217
/*
218
* Wait until the child has set its lock and then perform the
219
* test.
220
*/
221
if (read(pfd[0], &ch, 1) != 1)
222
err(1, "reading from pipe (child)");
223
224
/*
225
* fcntl should return -1 with errno set to either EACCES or
226
* EAGAIN.
227
*/
228
printf("2 - F_SETLK on locked region: ");
229
res = fcntl(fd, F_SETLK, &fl);
230
kill(pid, SIGTERM);
231
safe_waitpid(pid);
232
close(pfd[0]);
233
close(pfd[1]);
234
FAIL(res == 0);
235
FAIL(errno != EACCES && errno != EAGAIN);
236
237
SUCCEED;
238
}
239
240
/*
241
* Test 3 - F_SETLKW on locked region
242
*
243
* If a shared or exclusive lock is blocked by other locks, the
244
* process waits until the request can be satisfied.
245
*
246
* XXX this test hangs on FreeBSD NFS filesystems due to limitations
247
* in FreeBSD's client (and server) lockd implementation.
248
*/
249
static int
250
test3(int fd, __unused int argc, const __unused char **argv)
251
{
252
/*
253
* We create a child process to hold the lock which we will
254
* test. We use a pipe to communicate with the child.
255
*/
256
int pid;
257
int pfd[2];
258
struct flock fl;
259
char ch;
260
int res;
261
262
if (pipe(pfd) < 0)
263
err(1, "pipe");
264
265
fl.l_start = 0;
266
fl.l_len = 0;
267
fl.l_type = F_WRLCK;
268
fl.l_whence = SEEK_SET;
269
270
pid = fork();
271
if (pid < 0)
272
err(1, "fork");
273
274
if (pid == 0) {
275
/*
276
* We are the child. We set a write lock and then
277
* write one byte back to the parent to tell it. The
278
* parent will kill us when its done.
279
*/
280
if (fcntl(fd, F_SETLK, &fl) < 0)
281
err(1, "F_SETLK (child)");
282
if (write(pfd[1], "a", 1) < 0)
283
err(1, "writing to pipe (child)");
284
pause();
285
exit(0);
286
}
287
288
/*
289
* Wait until the child has set its lock and then perform the
290
* test.
291
*/
292
if (read(pfd[0], &ch, 1) != 1)
293
err(1, "reading from pipe (child)");
294
295
/*
296
* fcntl should wait until the alarm and then return -1 with
297
* errno set to EINTR.
298
*/
299
printf("3 - F_SETLKW on locked region: ");
300
301
alarm(1);
302
303
res = fcntl(fd, F_SETLKW, &fl);
304
kill(pid, SIGTERM);
305
safe_waitpid(pid);
306
close(pfd[0]);
307
close(pfd[1]);
308
FAIL(res == 0);
309
FAIL(errno != EINTR);
310
311
SUCCEED;
312
}
313
314
/*
315
* Test 4 - F_GETLK on locked region
316
*
317
* Get the first lock that blocks the lock.
318
*/
319
static int
320
test4(int fd, __unused int argc, const __unused char **argv)
321
{
322
/*
323
* We create a child process to hold the lock which we will
324
* test. We use a pipe to communicate with the child.
325
*/
326
int pid;
327
int pfd[2];
328
struct flock fl;
329
char ch;
330
331
if (pipe(pfd) < 0)
332
err(1, "pipe");
333
334
fl.l_start = 0;
335
fl.l_len = 99;
336
fl.l_type = F_WRLCK;
337
fl.l_whence = SEEK_SET;
338
339
pid = fork();
340
if (pid < 0)
341
err(1, "fork");
342
343
if (pid == 0) {
344
/*
345
* We are the child. We set a write lock and then
346
* write one byte back to the parent to tell it. The
347
* parent will kill us when its done.
348
*/
349
if (fcntl(fd, F_SETLK, &fl) < 0)
350
err(1, "F_SETLK (child)");
351
if (write(pfd[1], "a", 1) < 0)
352
err(1, "writing to pipe (child)");
353
pause();
354
exit(0);
355
}
356
357
/*
358
* Wait until the child has set its lock and then perform the
359
* test.
360
*/
361
if (read(pfd[0], &ch, 1) != 1)
362
err(1, "reading from pipe (child)");
363
364
/*
365
* fcntl should return a lock structure reflecting the lock we
366
* made in the child process.
367
*/
368
if (fcntl(fd, F_GETLK, &fl) < 0)
369
err(1, "F_GETLK");
370
371
printf("4 - F_GETLK on locked region: ");
372
FAIL(fl.l_start != 0);
373
FAIL(fl.l_len != 99);
374
FAIL(fl.l_type != F_WRLCK);
375
FAIL(fl.l_pid != pid);
376
#ifdef HAVE_SYSID
377
FAIL(fl.l_sysid != 0);
378
#endif
379
380
kill(pid, SIGTERM);
381
safe_waitpid(pid);
382
close(pfd[0]);
383
close(pfd[1]);
384
385
SUCCEED;
386
}
387
388
/*
389
* Test 5 - F_SETLKW simple deadlock
390
*
391
* If a blocking shared lock request would cause a deadlock (i.e. the
392
* lock request is blocked by a process which is itself blocked on a
393
* lock currently owned by the process making the new request),
394
* EDEADLK is returned.
395
*/
396
static int
397
test5(int fd, __unused int argc, const __unused char **argv)
398
{
399
/*
400
* We create a child process to hold the lock which we will
401
* test. Because our test relies on the child process being
402
* blocked on the parent's lock, we can't easily use a pipe to
403
* synchronize so we just sleep in the parent to given the
404
* child a chance to setup.
405
*
406
* To create the deadlock condition, we arrange for the parent
407
* to lock the first byte of the file and the child to lock
408
* the second byte. After locking the second byte, the child
409
* will attempt to lock the first byte of the file, and
410
* block. The parent will then attempt to lock the second byte
411
* (owned by the child) which should cause deadlock.
412
*/
413
int pid;
414
struct flock fl;
415
int res;
416
417
/*
418
* Lock the first byte in the parent.
419
*/
420
fl.l_start = 0;
421
fl.l_len = 1;
422
fl.l_type = F_WRLCK;
423
fl.l_whence = SEEK_SET;
424
if (fcntl(fd, F_SETLK, &fl) < 0)
425
err(1, "F_SETLK 1 (parent)");
426
427
pid = fork();
428
if (pid < 0)
429
err(1, "fork");
430
431
if (pid == 0) {
432
/*
433
* Lock the second byte in the child and then block on
434
* the parent's lock.
435
*/
436
fl.l_start = 1;
437
if (fcntl(fd, F_SETLK, &fl) < 0)
438
err(1, "F_SETLK (child)");
439
fl.l_start = 0;
440
if (fcntl(fd, F_SETLKW, &fl) < 0)
441
err(1, "F_SETLKW (child)");
442
exit(0);
443
}
444
445
/*
446
* Wait until the child has set its lock and then perform the
447
* test.
448
*/
449
sleep(1);
450
451
/*
452
* fcntl should immediately return -1 with errno set to
453
* EDEADLK. If the alarm fires, we failed to detect the
454
* deadlock.
455
*/
456
alarm(1);
457
printf("5 - F_SETLKW simple deadlock: ");
458
459
fl.l_start = 1;
460
res = fcntl(fd, F_SETLKW, &fl);
461
kill(pid, SIGTERM);
462
safe_waitpid(pid);
463
464
FAIL(res == 0);
465
FAIL(errno != EDEADLK);
466
467
fl.l_start = 0;
468
fl.l_len = 0;
469
fl.l_type = F_UNLCK;
470
if (fcntl(fd, F_SETLK, &fl) < 0)
471
err(1, "F_UNLCK");
472
473
/*
474
* Cancel the alarm to avoid confusing later tests.
475
*/
476
alarm(0);
477
478
SUCCEED;
479
}
480
481
/*
482
* Test 6 - F_SETLKW complex deadlock.
483
*
484
* This test involves three process, P, C1 and C2. We set things up so
485
* that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
486
* also block C2 by attempting to lock byte zero. Lastly, P attempts
487
* to lock a range including byte 1 and 2. This represents a deadlock
488
* (due to C2's blocking attempt to lock byte zero).
489
*/
490
static int
491
test6(int fd, __unused int argc, const __unused char **argv)
492
{
493
/*
494
* Because our test relies on the child process being blocked
495
* on the parent's lock, we can't easily use a pipe to
496
* synchronize so we just sleep in the parent to given the
497
* children a chance to setup.
498
*/
499
int pid1, pid2;
500
struct flock fl;
501
int res;
502
503
/*
504
* Lock the first byte in the parent.
505
*/
506
fl.l_start = 0;
507
fl.l_len = 1;
508
fl.l_type = F_WRLCK;
509
fl.l_whence = SEEK_SET;
510
if (fcntl(fd, F_SETLK, &fl) < 0)
511
err(1, "F_SETLK 1 (parent)");
512
513
pid1 = fork();
514
if (pid1 < 0)
515
err(1, "fork");
516
517
if (pid1 == 0) {
518
/*
519
* C1
520
* Lock the second byte in the child and then sleep
521
*/
522
fl.l_start = 1;
523
if (fcntl(fd, F_SETLK, &fl) < 0)
524
err(1, "F_SETLK (child1)");
525
pause();
526
exit(0);
527
}
528
529
pid2 = fork();
530
if (pid2 < 0)
531
err(1, "fork");
532
533
if (pid2 == 0) {
534
/*
535
* C2
536
* Lock the third byte in the child and then block on
537
* the parent's lock.
538
*/
539
fl.l_start = 2;
540
if (fcntl(fd, F_SETLK, &fl) < 0)
541
err(1, "F_SETLK (child2)");
542
fl.l_start = 0;
543
if (fcntl(fd, F_SETLKW, &fl) < 0)
544
err(1, "F_SETLKW (child2)");
545
exit(0);
546
}
547
548
/*
549
* Wait until the children have set their locks and then
550
* perform the test.
551
*/
552
sleep(1);
553
554
/*
555
* fcntl should immediately return -1 with errno set to
556
* EDEADLK. If the alarm fires, we failed to detect the
557
* deadlock.
558
*/
559
alarm(1);
560
printf("6 - F_SETLKW complex deadlock: ");
561
562
fl.l_start = 1;
563
fl.l_len = 2;
564
res = fcntl(fd, F_SETLKW, &fl);
565
kill(pid1, SIGTERM);
566
safe_waitpid(pid1);
567
kill(pid2, SIGTERM);
568
safe_waitpid(pid2);
569
570
fl.l_start = 0;
571
fl.l_len = 0;
572
fl.l_type = F_UNLCK;
573
if (fcntl(fd, F_SETLK, &fl) < 0)
574
err(1, "F_UNLCK");
575
576
FAIL(res == 0);
577
FAIL(errno != EDEADLK);
578
579
/*
580
* Cancel the alarm to avoid confusing later tests.
581
*/
582
alarm(0);
583
584
SUCCEED;
585
}
586
587
/*
588
* Test 7 - F_SETLK shared lock on exclusive locked region
589
*
590
* If a shared or exclusive lock cannot be set, fcntl returns
591
* immediately with EACCES or EAGAIN.
592
*/
593
static int
594
test7(int fd, __unused int argc, const __unused char **argv)
595
{
596
/*
597
* We create a child process to hold the lock which we will
598
* test. We use a pipe to communicate with the child.
599
*/
600
int pid;
601
int pfd[2];
602
struct flock fl;
603
char ch;
604
int res;
605
606
if (pipe(pfd) < 0)
607
err(1, "pipe");
608
609
fl.l_start = 0;
610
fl.l_len = 0;
611
fl.l_type = F_WRLCK;
612
fl.l_whence = SEEK_SET;
613
614
pid = fork();
615
if (pid < 0)
616
err(1, "fork");
617
618
if (pid == 0) {
619
/*
620
* We are the child. We set a write lock and then
621
* write one byte back to the parent to tell it. The
622
* parent will kill us when its done.
623
*/
624
if (fcntl(fd, F_SETLK, &fl) < 0)
625
err(1, "F_SETLK (child)");
626
if (write(pfd[1], "a", 1) < 0)
627
err(1, "writing to pipe (child)");
628
pause();
629
exit(0);
630
}
631
632
/*
633
* Wait until the child has set its lock and then perform the
634
* test.
635
*/
636
if (read(pfd[0], &ch, 1) != 1)
637
err(1, "reading from pipe (child)");
638
639
/*
640
* fcntl should wait until the alarm and then return -1 with
641
* errno set to EINTR.
642
*/
643
printf("7 - F_SETLK shared lock on exclusive locked region: ");
644
645
fl.l_type = F_RDLCK;
646
res = fcntl(fd, F_SETLK, &fl);
647
kill(pid, SIGTERM);
648
safe_waitpid(pid);
649
close(pfd[0]);
650
close(pfd[1]);
651
652
FAIL(res == 0);
653
FAIL(errno != EACCES && errno != EAGAIN);
654
655
SUCCEED;
656
}
657
658
/*
659
* Test 8 - F_SETLK shared lock on share locked region
660
*
661
* When a shared lock is set on a segment of a file, other processes
662
* shall be able to set shared locks on that segment or a portion of
663
* it.
664
*/
665
static int
666
test8(int fd, __unused int argc, const __unused char **argv)
667
{
668
/*
669
* We create a child process to hold the lock which we will
670
* test. We use a pipe to communicate with the child.
671
*/
672
int pid;
673
int pfd[2];
674
struct flock fl;
675
char ch;
676
int res;
677
678
if (pipe(pfd) < 0)
679
err(1, "pipe");
680
681
fl.l_start = 0;
682
fl.l_len = 0;
683
fl.l_type = F_RDLCK;
684
fl.l_whence = SEEK_SET;
685
686
pid = fork();
687
if (pid < 0)
688
err(1, "fork");
689
690
if (pid == 0) {
691
/*
692
* We are the child. We set a write lock and then
693
* write one byte back to the parent to tell it. The
694
* parent will kill us when its done.
695
*/
696
if (fcntl(fd, F_SETLK, &fl) < 0)
697
err(1, "F_SETLK (child)");
698
if (write(pfd[1], "a", 1) < 0)
699
err(1, "writing to pipe (child)");
700
pause();
701
exit(0);
702
}
703
704
/*
705
* Wait until the child has set its lock and then perform the
706
* test.
707
*/
708
if (read(pfd[0], &ch, 1) != 1)
709
err(1, "reading from pipe (child)");
710
711
/*
712
* fcntl should wait until the alarm and then return -1 with
713
* errno set to EINTR.
714
*/
715
printf("8 - F_SETLK shared lock on share locked region: ");
716
717
fl.l_type = F_RDLCK;
718
res = fcntl(fd, F_SETLK, &fl);
719
720
kill(pid, SIGTERM);
721
safe_waitpid(pid);
722
close(pfd[0]);
723
close(pfd[1]);
724
725
fl.l_start = 0;
726
fl.l_len = 0;
727
fl.l_type = F_UNLCK;
728
if (fcntl(fd, F_SETLK, &fl) < 0)
729
err(1, "F_UNLCK");
730
731
FAIL(res != 0);
732
733
SUCCEED;
734
}
735
736
/*
737
* Test 9 - F_SETLK exclusive lock on share locked region
738
*
739
* If a shared or exclusive lock cannot be set, fcntl returns
740
* immediately with EACCES or EAGAIN.
741
*/
742
static int
743
test9(int fd, __unused int argc, const __unused char **argv)
744
{
745
/*
746
* We create a child process to hold the lock which we will
747
* test. We use a pipe to communicate with the child.
748
*/
749
int pid;
750
int pfd[2];
751
struct flock fl;
752
char ch;
753
int res;
754
755
if (pipe(pfd) < 0)
756
err(1, "pipe");
757
758
fl.l_start = 0;
759
fl.l_len = 0;
760
fl.l_type = F_RDLCK;
761
fl.l_whence = SEEK_SET;
762
763
pid = fork();
764
if (pid < 0)
765
err(1, "fork");
766
767
if (pid == 0) {
768
/*
769
* We are the child. We set a write lock and then
770
* write one byte back to the parent to tell it. The
771
* parent will kill us when its done.
772
*/
773
if (fcntl(fd, F_SETLK, &fl) < 0)
774
err(1, "F_SETLK (child)");
775
if (write(pfd[1], "a", 1) < 0)
776
err(1, "writing to pipe (child)");
777
pause();
778
exit(0);
779
}
780
781
/*
782
* Wait until the child has set its lock and then perform the
783
* test.
784
*/
785
if (read(pfd[0], &ch, 1) != 1)
786
err(1, "reading from pipe (child)");
787
788
/*
789
* fcntl should wait until the alarm and then return -1 with
790
* errno set to EINTR.
791
*/
792
printf("9 - F_SETLK exclusive lock on share locked region: ");
793
794
fl.l_type = F_WRLCK;
795
res = fcntl(fd, F_SETLK, &fl);
796
kill(pid, SIGTERM);
797
safe_waitpid(pid);
798
close(pfd[0]);
799
close(pfd[1]);
800
801
FAIL(res == 0);
802
FAIL(errno != EACCES && errno != EAGAIN);
803
804
SUCCEED;
805
}
806
807
/*
808
* Test 10 - trying to set bogus pid or sysid values
809
*
810
* The l_pid and l_sysid fields are only used with F_GETLK to return
811
* the process ID of the process holding a blocking lock and the
812
* system ID of the system that owns that process
813
*/
814
static int
815
test10(int fd, __unused int argc, const __unused char **argv)
816
{
817
/*
818
* We create a child process to hold the lock which we will
819
* test. We use a pipe to communicate with the child.
820
*/
821
int pid;
822
int pfd[2];
823
struct flock fl;
824
char ch;
825
826
if (pipe(pfd) < 0)
827
err(1, "pipe");
828
829
fl.l_start = 0;
830
fl.l_len = 0;
831
fl.l_type = F_WRLCK;
832
fl.l_whence = SEEK_SET;
833
fl.l_pid = 9999;
834
#ifdef HAVE_SYSID
835
fl.l_sysid = 9999;
836
#endif
837
838
pid = fork();
839
if (pid < 0)
840
err(1, "fork");
841
842
if (pid == 0) {
843
/*
844
* We are the child. We set a write lock and then
845
* write one byte back to the parent to tell it. The
846
* parent will kill us when its done.
847
*/
848
if (fcntl(fd, F_SETLK, &fl) < 0)
849
err(1, "F_SETLK (child)");
850
if (write(pfd[1], "a", 1) < 0)
851
err(1, "writing to pipe (child)");
852
pause();
853
exit(0);
854
}
855
856
/*
857
* Wait until the child has set its lock and then perform the
858
* test.
859
*/
860
if (read(pfd[0], &ch, 1) != 1)
861
err(1, "reading from pipe (child)");
862
863
printf("10 - trying to set bogus pid or sysid values: ");
864
865
if (fcntl(fd, F_GETLK, &fl) < 0)
866
err(1, "F_GETLK");
867
868
kill(pid, SIGTERM);
869
safe_waitpid(pid);
870
close(pfd[0]);
871
close(pfd[1]);
872
873
FAIL(fl.l_pid != pid);
874
#ifdef HAVE_SYSID
875
FAIL(fl.l_sysid != 0);
876
#endif
877
878
SUCCEED;
879
}
880
881
/*
882
* Test 11 - remote locks
883
*
884
* XXX temporary interface which will be removed when the kernel lockd
885
* is added.
886
*/
887
static int
888
test11(int fd, __unused int argc, const __unused char **argv)
889
{
890
#ifdef F_SETLK_REMOTE
891
struct flock fl;
892
int res;
893
894
if (geteuid() != 0)
895
return 0;
896
897
fl.l_start = 0;
898
fl.l_len = 0;
899
fl.l_type = F_WRLCK;
900
fl.l_whence = SEEK_SET;
901
fl.l_pid = 9999;
902
fl.l_sysid = 1001;
903
904
printf("11 - remote locks: ");
905
906
res = fcntl(fd, F_SETLK_REMOTE, &fl);
907
FAIL(res != 0);
908
909
fl.l_sysid = 1002;
910
res = fcntl(fd, F_SETLK_REMOTE, &fl);
911
FAIL(res == 0);
912
FAIL(errno != EACCES && errno != EAGAIN);
913
914
res = fcntl(fd, F_GETLK, &fl);
915
FAIL(res != 0);
916
FAIL(fl.l_pid != 9999);
917
FAIL(fl.l_sysid != 1001);
918
919
fl.l_type = F_UNLCK;
920
fl.l_sysid = 1001;
921
fl.l_start = 0;
922
fl.l_len = 0;
923
res = fcntl(fd, F_SETLK_REMOTE, &fl);
924
FAIL(res != 0);
925
926
fl.l_pid = 1234;
927
fl.l_sysid = 1001;
928
fl.l_start = 0;
929
fl.l_len = 1;
930
fl.l_whence = SEEK_SET;
931
fl.l_type = F_RDLCK;
932
res = fcntl(fd, F_SETLK_REMOTE, &fl);
933
FAIL(res != 0);
934
935
fl.l_sysid = 1002;
936
res = fcntl(fd, F_SETLK_REMOTE, &fl);
937
FAIL(res != 0);
938
939
fl.l_type = F_UNLCKSYS;
940
fl.l_sysid = 1001;
941
res = fcntl(fd, F_SETLK_REMOTE, &fl);
942
FAIL(res != 0);
943
944
fl.l_type = F_WRLCK;
945
res = fcntl(fd, F_GETLK, &fl);
946
FAIL(res != 0);
947
FAIL(fl.l_pid != 1234);
948
FAIL(fl.l_sysid != 1002);
949
950
fl.l_type = F_UNLCKSYS;
951
fl.l_sysid = 1002;
952
res = fcntl(fd, F_SETLK_REMOTE, &fl);
953
FAIL(res != 0);
954
955
SUCCEED;
956
#else
957
return 0;
958
#endif
959
}
960
961
/*
962
* Test 12 - F_SETLKW on locked region which is then unlocked
963
*
964
* If a shared or exclusive lock is blocked by other locks, the
965
* process waits until the request can be satisfied.
966
*/
967
static int
968
test12(int fd, __unused int argc, const __unused char **argv)
969
{
970
/*
971
* We create a child process to hold the lock which we will
972
* test. We use a pipe to communicate with the child.
973
*/
974
int pid;
975
int pfd[2];
976
struct flock fl;
977
char ch;
978
int res;
979
980
if (pipe(pfd) < 0)
981
err(1, "pipe");
982
983
fl.l_start = 0;
984
fl.l_len = 0;
985
fl.l_type = F_WRLCK;
986
fl.l_whence = SEEK_SET;
987
988
pid = fork();
989
if (pid < 0)
990
err(1, "fork");
991
992
if (pid == 0) {
993
/*
994
* We are the child. We set a write lock and then
995
* write one byte back to the parent to tell it. The
996
* parent will kill us when its done.
997
*/
998
if (fcntl(fd, F_SETLK, &fl) < 0)
999
err(1, "F_SETLK (child)");
1000
if (write(pfd[1], "a", 1) < 0)
1001
err(1, "writing to pipe (child)");
1002
1003
sleep(1);
1004
exit(0);
1005
}
1006
1007
/*
1008
* Wait until the child has set its lock and then perform the
1009
* test.
1010
*/
1011
if (read(pfd[0], &ch, 1) != 1)
1012
err(1, "reading from pipe (child)");
1013
1014
/*
1015
* fcntl should wait until the alarm and then return -1 with
1016
* errno set to EINTR.
1017
*/
1018
printf("12 - F_SETLKW on locked region which is then unlocked: ");
1019
1020
//alarm(1);
1021
1022
res = fcntl(fd, F_SETLKW, &fl);
1023
kill(pid, SIGTERM);
1024
safe_waitpid(pid);
1025
close(pfd[0]);
1026
close(pfd[1]);
1027
FAIL(res != 0);
1028
1029
fl.l_start = 0;
1030
fl.l_len = 0;
1031
fl.l_type = F_UNLCK;
1032
if (fcntl(fd, F_SETLK, &fl) < 0)
1033
err(1, "F_UNLCK");
1034
1035
SUCCEED;
1036
}
1037
1038
/*
1039
* Test 13 - F_SETLKW on locked region, race with owner
1040
*
1041
* If a shared or exclusive lock is blocked by other locks, the
1042
* process waits until the request can be satisfied.
1043
*/
1044
static int
1045
test13(int fd, __unused int argc, const __unused char **argv)
1046
{
1047
/*
1048
* We create a child process to hold the lock which we will
1049
* test. We use a pipe to communicate with the child.
1050
*/
1051
int i;
1052
int pid;
1053
int pfd[2];
1054
struct flock fl;
1055
char ch;
1056
int res;
1057
struct itimerval itv;
1058
1059
printf("13 - F_SETLKW on locked region, race with owner: ");
1060
fflush(stdout);
1061
1062
for (i = 0; i < 100; i++) {
1063
if (pipe(pfd) < 0)
1064
err(1, "pipe");
1065
1066
fl.l_start = 0;
1067
fl.l_len = 0;
1068
fl.l_type = F_WRLCK;
1069
fl.l_whence = SEEK_SET;
1070
1071
pid = fork();
1072
if (pid < 0)
1073
err(1, "fork");
1074
1075
if (pid == 0) {
1076
/*
1077
* We are the child. We set a write lock and then
1078
* write one byte back to the parent to tell it. The
1079
* parent will kill us when its done.
1080
*/
1081
if (fcntl(fd, F_SETLK, &fl) < 0)
1082
err(1, "F_SETLK (child)");
1083
if (write(pfd[1], "a", 1) < 0)
1084
err(1, "writing to pipe (child)");
1085
1086
usleep(1);
1087
exit(0);
1088
}
1089
1090
/*
1091
* Wait until the child has set its lock and then perform the
1092
* test.
1093
*/
1094
while (read(pfd[0], &ch, 1) != 1) {
1095
if (errno == EINTR)
1096
continue;
1097
err(1, "reading from pipe (child)");
1098
}
1099
1100
/*
1101
* fcntl should wait until the alarm and then return -1 with
1102
* errno set to EINTR.
1103
*/
1104
itv.it_interval.tv_sec = 0;
1105
itv.it_interval.tv_usec = 0;
1106
itv.it_value.tv_sec = 0;
1107
itv.it_value.tv_usec = 2;
1108
setitimer(ITIMER_REAL, &itv, NULL);
1109
1110
res = fcntl(fd, F_SETLKW, &fl);
1111
kill(pid, SIGTERM);
1112
safe_waitpid(pid);
1113
close(pfd[0]);
1114
close(pfd[1]);
1115
FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
1116
1117
fl.l_start = 0;
1118
fl.l_len = 0;
1119
fl.l_type = F_UNLCK;
1120
if (fcntl(fd, F_SETLK, &fl) < 0)
1121
err(1, "F_UNLCK");
1122
}
1123
SUCCEED;
1124
}
1125
1126
/*
1127
* Test 14 - soak test
1128
*/
1129
static int
1130
test14(int fd, int argc, const char **argv)
1131
{
1132
#define CHILD_COUNT 20
1133
/*
1134
* We create a set of child processes and let each one run
1135
* through a random sequence of locks and unlocks.
1136
*/
1137
int i, j, id, id_base;
1138
int pids[CHILD_COUNT], pid;
1139
char buf[128];
1140
char tbuf[128];
1141
int map[128];
1142
char outbuf[512];
1143
struct flock fl;
1144
struct itimerval itv;
1145
int status;
1146
1147
id_base = 0;
1148
if (argc >= 2)
1149
id_base = strtol(argv[1], NULL, 0);
1150
1151
printf("14 - soak test: ");
1152
fflush(stdout);
1153
1154
for (i = 0; i < 128; i++)
1155
map[i] = F_UNLCK;
1156
1157
for (i = 0; i < CHILD_COUNT; i++) {
1158
1159
pid = fork();
1160
if (pid < 0)
1161
err(1, "fork");
1162
if (pid) {
1163
/*
1164
* Parent - record the pid and continue.
1165
*/
1166
pids[i] = pid;
1167
continue;
1168
}
1169
1170
/*
1171
* Child - do some work and exit.
1172
*/
1173
id = id_base + i;
1174
srandom(getpid());
1175
1176
for (j = 0; j < 50; j++) {
1177
int start, end, len;
1178
int set, wrlock;
1179
1180
do {
1181
start = random() & 127;
1182
end = random() & 127;
1183
} while (end <= start);
1184
1185
set = random() & 1;
1186
wrlock = random() & 1;
1187
1188
len = end - start;
1189
fl.l_start = start;
1190
fl.l_len = len;
1191
fl.l_whence = SEEK_SET;
1192
if (set)
1193
fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
1194
else
1195
fl.l_type = F_UNLCK;
1196
1197
itv.it_interval.tv_sec = 0;
1198
itv.it_interval.tv_usec = 0;
1199
itv.it_value.tv_sec = 0;
1200
itv.it_value.tv_usec = 3000;
1201
setitimer(ITIMER_REAL, &itv, NULL);
1202
1203
if (fcntl(fd, F_SETLKW, &fl) < 0) {
1204
if (errno == EDEADLK || errno == EINTR) {
1205
if (verbose) {
1206
snprintf(outbuf, sizeof(outbuf),
1207
"%d[%d]: %s [%d .. %d] %s\n",
1208
id, j,
1209
set ? (wrlock ? "write lock"
1210
: "read lock")
1211
: "unlock", start, end,
1212
errno == EDEADLK
1213
? "deadlock"
1214
: "interrupted");
1215
write(1, outbuf,
1216
strlen(outbuf));
1217
}
1218
continue;
1219
} else {
1220
perror("fcntl");
1221
}
1222
}
1223
1224
itv.it_interval.tv_sec = 0;
1225
itv.it_interval.tv_usec = 0;
1226
itv.it_value.tv_sec = 0;
1227
itv.it_value.tv_usec = 0;
1228
setitimer(ITIMER_REAL, &itv, NULL);
1229
1230
if (verbose) {
1231
snprintf(outbuf, sizeof(outbuf),
1232
"%d[%d]: %s [%d .. %d] succeeded\n",
1233
id, j,
1234
set ? (wrlock ? "write lock" : "read lock")
1235
: "unlock", start, end);
1236
write(1, outbuf, strlen(outbuf));
1237
}
1238
1239
if (set) {
1240
if (wrlock) {
1241
/*
1242
* We got a write lock - write
1243
* our ID to each byte that we
1244
* managed to claim.
1245
*/
1246
for (i = start; i < end; i++)
1247
map[i] = F_WRLCK;
1248
memset(&buf[start], id, len);
1249
if (pwrite(fd, &buf[start], len,
1250
start) != len) {
1251
printf("%d: short write\n", id);
1252
exit(1);
1253
}
1254
} else {
1255
/*
1256
* We got a read lock - read
1257
* the bytes which we claimed
1258
* so that we can check that
1259
* they don't change
1260
* unexpectedly.
1261
*/
1262
for (i = start; i < end; i++)
1263
map[i] = F_RDLCK;
1264
if (pread(fd, &buf[start], len,
1265
start) != len) {
1266
printf("%d: short read\n", id);
1267
exit(1);
1268
}
1269
}
1270
} else {
1271
for (i = start; i < end; i++)
1272
map[i] = F_UNLCK;
1273
}
1274
1275
usleep(1000);
1276
1277
/*
1278
* Read back the whole region so that we can
1279
* check that all the bytes we have some kind
1280
* of claim to have the correct value.
1281
*/
1282
if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
1283
printf("%d: short read\n", id);
1284
exit(1);
1285
}
1286
1287
for (i = 0; i < 128; i++) {
1288
if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
1289
snprintf(outbuf, sizeof(outbuf),
1290
"%d: byte %d expected %d, "
1291
"got %d\n", id, i, buf[i], tbuf[i]);
1292
write(1, outbuf, strlen(outbuf));
1293
exit(1);
1294
}
1295
}
1296
}
1297
if (verbose)
1298
printf("%d[%d]: done\n", id, j);
1299
1300
exit(0);
1301
}
1302
1303
status = 0;
1304
for (i = 0; i < CHILD_COUNT; i++) {
1305
status += safe_waitpid(pids[i]);
1306
}
1307
if (status)
1308
FAIL(status != 0);
1309
1310
SUCCEED;
1311
}
1312
1313
/*
1314
* Test 15 - flock(2) semantcs
1315
*
1316
* When a lock holder has a shared lock and attempts to upgrade that
1317
* shared lock to exclusive, it must drop the shared lock before
1318
* blocking on the exclusive lock.
1319
*
1320
* To test this, we first arrange for two shared locks on the file,
1321
* and then attempt to upgrade one of them to exclusive. This should
1322
* drop one of the shared locks and block. We interrupt the blocking
1323
* lock request and examine the lock state of the file after dropping
1324
* the other shared lock - there should be no active locks at this
1325
* point.
1326
*/
1327
static int
1328
test15(int fd, __unused int argc, const __unused char **argv)
1329
{
1330
#ifdef LOCK_EX
1331
/*
1332
* We create a child process to hold the lock which we will
1333
* test. We use a pipe to communicate with the child.
1334
*
1335
* Since we only have one file descriptors and lock ownership
1336
* for flock(2) goes with the file descriptor, we use fcntl to
1337
* set the child's shared lock.
1338
*/
1339
int pid;
1340
int pfd[2];
1341
struct flock fl;
1342
char ch;
1343
int res;
1344
1345
if (pipe(pfd) < 0)
1346
err(1, "pipe");
1347
1348
pid = fork();
1349
if (pid < 0)
1350
err(1, "fork");
1351
1352
if (pid == 0) {
1353
/*
1354
* We are the child. We set a shared lock and then
1355
* write one byte back to the parent to tell it. The
1356
* parent will kill us when its done.
1357
*/
1358
fl.l_start = 0;
1359
fl.l_len = 0;
1360
fl.l_type = F_RDLCK;
1361
fl.l_whence = SEEK_SET;
1362
if (fcntl(fd, F_SETLK, &fl) < 0)
1363
err(1, "fcntl(F_SETLK) (child)");
1364
if (write(pfd[1], "a", 1) < 0)
1365
err(1, "writing to pipe (child)");
1366
pause();
1367
exit(0);
1368
}
1369
1370
/*
1371
* Wait until the child has set its lock and then perform the
1372
* test.
1373
*/
1374
if (read(pfd[0], &ch, 1) != 1)
1375
err(1, "reading from pipe (child)");
1376
1377
(void)dup(fd);
1378
if (flock(fd, LOCK_SH) < 0)
1379
err(1, "flock shared");
1380
1381
/*
1382
* flock should wait until the alarm and then return -1 with
1383
* errno set to EINTR.
1384
*/
1385
printf("15 - flock(2) semantics: ");
1386
1387
alarm(1);
1388
flock(fd, LOCK_EX);
1389
1390
/*
1391
* Kill the child to force it to drop its locks.
1392
*/
1393
kill(pid, SIGTERM);
1394
safe_waitpid(pid);
1395
1396
fl.l_start = 0;
1397
fl.l_len = 0;
1398
fl.l_type = F_WRLCK;
1399
fl.l_whence = SEEK_SET;
1400
res = fcntl(fd, F_GETLK, &fl);
1401
1402
close(pfd[0]);
1403
close(pfd[1]);
1404
FAIL(res != 0);
1405
FAIL(fl.l_type != F_UNLCK);
1406
1407
SUCCEED;
1408
#else
1409
return 0;
1410
#endif
1411
}
1412
1413
struct test_ctx {
1414
struct flock tc_fl;
1415
int tc_fd;
1416
};
1417
1418
static void *
1419
test16_func(void *tc_in)
1420
{
1421
uintptr_t error;
1422
struct test_ctx *tc = tc_in;
1423
1424
error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
1425
1426
pthread_exit((void *)error);
1427
}
1428
1429
#define THREADS 10
1430
1431
/*
1432
* Test 16 - F_SETLKW from two threads
1433
*
1434
* If two threads within a process are blocked on a lock and the lock
1435
* is granted, make sure things are sane.
1436
*/
1437
static int
1438
test16(int fd, __unused int argc, const __unused char **argv)
1439
{
1440
/*
1441
* We create a child process to hold the lock which we will
1442
* test. We use a pipe to communicate with the child.
1443
*/
1444
int pid;
1445
int pfd[2];
1446
struct test_ctx tc = { .tc_fd = fd };
1447
char ch;
1448
int i;
1449
int error;
1450
pthread_t thr[THREADS];
1451
1452
if (pipe(pfd) < 0)
1453
err(1, "pipe");
1454
1455
tc.tc_fl.l_start = 0;
1456
tc.tc_fl.l_len = 0;
1457
tc.tc_fl.l_type = F_WRLCK;
1458
tc.tc_fl.l_whence = SEEK_SET;
1459
1460
pid = fork();
1461
if (pid < 0)
1462
err(1, "fork");
1463
1464
if (pid == 0) {
1465
/*
1466
* We are the child. We set a write lock and then
1467
* write one byte back to the parent to tell it. The
1468
* parent will kill us when its done.
1469
*/
1470
if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
1471
err(1, "F_SETLK (child)");
1472
if (write(pfd[1], "a", 1) < 0)
1473
err(1, "writing to pipe (child)");
1474
pause();
1475
exit(0);
1476
}
1477
1478
/*
1479
* Wait until the child has set its lock and then perform the
1480
* test.
1481
*/
1482
if (read(pfd[0], &ch, 1) != 1)
1483
err(1, "reading from pipe (child)");
1484
1485
/*
1486
* fcntl should wait until the alarm and then return -1 with
1487
* errno set to EINTR.
1488
*/
1489
printf("16 - F_SETLKW on locked region by two threads: ");
1490
1491
for (i = 0; i < THREADS; i++) {
1492
error = pthread_create(&thr[i], NULL, test16_func, &tc);
1493
if (error)
1494
err(1, "pthread_create");
1495
}
1496
1497
/*
1498
* Sleep, then kill the child. This makes me a little sad, but it's
1499
* tricky to tell whether the threads are all really blocked by this
1500
* point.
1501
*/
1502
sleep(1);
1503
kill(pid, SIGTERM);
1504
safe_waitpid(pid);
1505
close(pfd[0]);
1506
close(pfd[1]);
1507
1508
for (i = 0; i < THREADS; i++) {
1509
void *res;
1510
error = pthread_join(thr[i], &res);
1511
if (error)
1512
err(1, "pthread_join");
1513
FAIL((uintptr_t)res != 0);
1514
}
1515
1516
SUCCEED;
1517
}
1518
1519
struct test {
1520
int (*testfn)(int, int, const char **); /* function to perform the test */
1521
int num; /* test number */
1522
int intr; /* non-zero if the test interrupts a lock */
1523
};
1524
1525
static struct test tests[] = {
1526
{ test1, 1, 0 },
1527
{ test2, 2, 0 },
1528
{ test3, 3, 1 },
1529
{ test4, 4, 0 },
1530
{ test5, 5, 1 },
1531
{ test6, 6, 1 },
1532
{ test7, 7, 0 },
1533
{ test8, 8, 0 },
1534
{ test9, 9, 0 },
1535
{ test10, 10, 0 },
1536
{ test11, 11, 1 },
1537
{ test12, 12, 0 },
1538
{ test13, 13, 1 },
1539
{ test14, 14, 0 },
1540
{ test15, 15, 1 },
1541
{ test16, 16, 1 },
1542
};
1543
1544
int
1545
main(int argc, const char *argv[])
1546
{
1547
int testnum;
1548
int fd;
1549
int nointr;
1550
unsigned i;
1551
struct sigaction sa;
1552
int test_argc;
1553
const char **test_argv;
1554
1555
if (argc < 2) {
1556
errx(1, "usage: flock <directory> [test number] ...");
1557
}
1558
1559
fd = make_file(argv[1], 1024);
1560
if (argc >= 3) {
1561
testnum = strtol(argv[2], NULL, 0);
1562
test_argc = argc - 2;
1563
test_argv = argv + 2;
1564
} else {
1565
testnum = 0;
1566
test_argc = 0;
1567
test_argv = NULL;
1568
}
1569
1570
sa.sa_handler = ignore_alarm;
1571
sigemptyset(&sa.sa_mask);
1572
sa.sa_flags = 0;
1573
sigaction(SIGALRM, &sa, 0);
1574
1575
nointr = 0;
1576
#if defined(__FreeBSD__) && __FreeBSD_version < 800040
1577
{
1578
/*
1579
* FreeBSD with userland NLM can't interrupt a blocked
1580
* lock request on an NFS mounted filesystem.
1581
*/
1582
struct statfs st;
1583
fstatfs(fd, &st);
1584
nointr = !strcmp(st.f_fstypename, "nfs");
1585
}
1586
#endif
1587
1588
for (i = 0; i < nitems(tests); i++) {
1589
if (tests[i].intr && nointr)
1590
continue;
1591
if (!testnum || tests[i].num == testnum)
1592
tests[i].testfn(fd, test_argc, test_argv);
1593
}
1594
1595
return 0;
1596
}
1597
1598