xref: /freebsd/tools/test/stress2/misc/fcntl.sh (revision ec0ea6efa1ad229d75c394c1a9b9cac33af2b1d3)
1#!/bin/sh
2
3#
4# Copyright (c) 2014 EMC Corp.
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# fcntl(2) locking scenario. No problems seen.
30
31. ../default.cfg
32
33here=`pwd`
34cd /tmp
35sed '1,/^EOF/d' < $here/$0 > fcntl.c
36mycc -o fcntl -Wall -Wextra -O0 -g fcntl.c || exit 1
37rm -f fcntl.c
38
39mkdir -p $RUNDIR
40cd $RUNDIR
41/tmp/fcntl
42status=$?
43
44rm -f /tmp/fcntl
45exit $status
46EOF
47#include <sys/types.h>
48#include <err.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <signal.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <sys/wait.h>
56#include <unistd.h>
57
58#define PARALLEL 16
59#define N 4096
60
61static volatile sig_atomic_t completed;
62const char name[] = "work";
63int fd;
64
65static void
66ahandler(int s __unused)
67{
68	unlink(name);
69	_exit(1);
70}
71
72static void
73handler(int s __unused)
74{
75	completed++;
76}
77
78void
79add(int n, int increment)
80{
81        struct flock fl;
82	off_t pos;
83	long val, oval;
84	int r;
85
86	pos = n * sizeof(val);
87	memset(&fl, 0, sizeof(fl));
88        fl.l_start = pos;
89        fl.l_len = sizeof(val);
90        fl.l_type = F_WRLCK;
91        fl.l_whence = SEEK_SET;
92
93	while (fcntl(fd, F_SETLK, &fl) < 0) {
94		if (errno != EAGAIN)
95			err(1, "F_SETLK (child)");
96		usleep(100);
97	}
98
99	if (lseek(fd, pos, SEEK_SET) == -1)
100		err(1, "lseek");
101	oval = 999999;
102	while ((r = read(fd, &val, sizeof(val)) != sizeof(val))) {
103		if (r == -1 && errno != EAGAIN)
104			err(1, "read");
105		if (lseek(fd, pos, SEEK_SET) == -1)
106			err(1, "lseek");
107	}
108	oval = val;
109	val = val + increment;
110#if defined(DEBUG)
111	fprintf(stderr, "add(%d, %d) @ pos %ld: %ld = %ld + %d\n",
112	    n, increment, (long)pos, val, oval, increment);
113#endif
114	if (lseek(fd, pos, SEEK_SET) == -1)
115		err(1, "lseek");
116	while ((r = write(fd, &val, sizeof(val)) != sizeof(val))) {
117		if (r == -1 && errno != EAGAIN)
118			err(1, "write");
119		if (lseek(fd, pos, SEEK_SET) == -1)
120			err(1, "lseek");
121	}
122
123        fl.l_type = F_UNLCK;
124        if (fcntl(fd, F_SETLK, &fl) < 0)
125                err(1, "F_UNLCK");
126
127}
128
129void
130up(void)
131{
132	int flags, i;
133
134	/* Need to re-open after a fork() */
135	close(fd);
136	if ((fd = open(name, O_RDWR)) == -1)
137		err(1, "open(%s)", name);
138        if ((flags = fcntl(fd, F_GETFL)) == -1)
139		err(1, "fcntl(%d, T_GETFL)", fd);
140        flags |= O_NONBLOCK;
141        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
142		err(1, "fcntl(%d, T_SETFL, %d)", fd, flags);
143
144	for (i = 0; i < N; i++)
145		add(i, 1);
146
147	kill(getppid(), SIGHUP);
148	while (access("work", R_OK) == 0)
149		usleep(100);
150
151	_exit(0);
152}
153
154void
155down(void)
156{
157	int flags, i;
158
159	close(fd);
160	if ((fd = open(name, O_RDWR)) == -1)
161		err(1, "open(%s)", name);
162        if ((flags = fcntl(fd, F_GETFL)) == -1)
163		err(1, "fcntl(%d, T_GETFL)", fd);
164        flags |= O_NONBLOCK;
165        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
166		err(1, "fcntl(%d, T_SETFL, %d)", fd, flags);
167
168	for (i = 0; i < N; i++)
169		add(i, -1);
170
171	kill(getppid(), SIGHUP);
172	while (access("work", R_OK) == 0)
173		usleep(100);
174
175	_exit(0);
176}
177
178int
179main(void)
180{
181	int flags, i;
182	long val, sum;
183	off_t len;
184
185	signal(SIGHUP, handler);
186	signal(SIGALRM, ahandler);
187	alarm(300);
188	if ((fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
189		err(1, "open(%s)", name);
190	len = N * sizeof(val);
191	if (ftruncate(fd, len) == -1)
192		err(1, "ftruncate");
193
194        if ((flags = fcntl(fd, F_GETFL)) == -1)
195		err(1, "fcntl(%d, T_GETFL)", fd);
196        flags |= O_NONBLOCK;
197        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
198		err(1, "fcntl(%d, T_SETFL, %d)", fd, flags);
199
200	for (i = 0; i < PARALLEL; i++) {
201		if (fork() == 0)
202			up();
203	}
204	for (i = 0; i < PARALLEL; i++) {
205		if (fork() == 0)
206			down();
207	}
208
209	while (completed != PARALLEL * 2)
210		usleep(200);
211
212	if (lseek(fd, 0, SEEK_SET) == -1)
213		err(1, "lseek");
214	sum = 0;
215	for (i = 0; i < N; i++) {
216		if (read(fd, &val, sizeof(val)) != sizeof(val))
217			err(1, "Final read");
218		if (val != 0)
219			fprintf(stderr, "index %d: %ld\n", i, val);
220		sum += val;
221	}
222	if (sum != 0)
223		fprintf(stderr, "FAIL\n");
224	unlink(name);
225
226	for (i = 0; i < PARALLEL; i++) {
227		wait(NULL);
228		wait(NULL);
229	}
230
231	close(fd);
232
233	return (sum != 0);
234}
235