xref: /freebsd/tools/test/stress2/misc/fcntl.sh (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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.
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 <sys/wait.h>
49
50#include <err.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <signal.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <string.h>
57#include <unistd.h>
58
59#define PARALLEL 16
60#define N 4096
61
62static volatile sig_atomic_t completed;
63const char name[] = "work";
64int fd;
65
66static void
67ahandler(int s __unused)
68{
69	unlink(name);
70	_exit(1);
71}
72
73static void
74handler(int s __unused)
75{
76	completed++;
77}
78
79void
80add(int n, int increment)
81{
82        struct flock fl;
83	off_t pos;
84	long val, oval;
85	int debug, r;
86
87	debug = 0; /* set to "1" for debug output. */
88	pos = n * sizeof(val);
89	memset(&fl, 0, sizeof(fl));
90        fl.l_start = pos;
91        fl.l_len = sizeof(val);
92        fl.l_type = F_WRLCK;
93        fl.l_whence = SEEK_SET;
94
95	while (fcntl(fd, F_SETLK, &fl) < 0) {
96		if (errno != EAGAIN)
97			err(1, "F_SETLK (child)");
98		usleep(100);
99	}
100
101	if (lseek(fd, pos, SEEK_SET) == -1)
102		err(1, "lseek");
103	oval = 999999;
104	while ((r = read(fd, &val, sizeof(val)) != sizeof(val))) {
105		if (r == -1 && errno != EAGAIN)
106			err(1, "read");
107		if (lseek(fd, pos, SEEK_SET) == -1)
108			err(1, "lseek");
109	}
110	oval = val;
111	val = val + increment;
112	if (debug != 0)
113		fprintf(stderr, "add(%d, %d) @ pos %ld: %ld = %ld + %d\n",
114		    n, increment, (long)pos, val, oval, increment);
115	if (lseek(fd, pos, SEEK_SET) == -1)
116		err(1, "lseek");
117	while ((r = write(fd, &val, sizeof(val)) != sizeof(val))) {
118		if (r == -1 && errno != EAGAIN)
119			err(1, "write");
120		if (lseek(fd, pos, SEEK_SET) == -1)
121			err(1, "lseek");
122	}
123
124        fl.l_type = F_UNLCK;
125        if (fcntl(fd, F_SETLK, &fl) < 0)
126                err(1, "F_UNLCK");
127
128}
129
130void
131up(void)
132{
133	int flags, i;
134
135	/* Need to re-open after a fork() */
136	close(fd);
137	if ((fd = open(name, O_RDWR)) == -1)
138		err(1, "open(%s)", name);
139        if ((flags = fcntl(fd, F_GETFL)) == -1)
140		err(1, "fcntl(%d, T_GETFL)", fd);
141        flags |= O_NONBLOCK;
142        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
143		err(1, "fcntl(%d, T_SETFL, %d)", fd, flags);
144
145	for (i = 0; i < N; i++)
146		add(i, 1);
147
148	kill(getppid(), SIGHUP);
149	while (access("work", R_OK) == 0)
150		usleep(100);
151
152	_exit(0);
153}
154
155void
156down(void)
157{
158	int flags, i;
159
160	close(fd);
161	if ((fd = open(name, O_RDWR)) == -1)
162		err(1, "open(%s)", name);
163        if ((flags = fcntl(fd, F_GETFL)) == -1)
164		err(1, "fcntl(%d, T_GETFL)", fd);
165        flags |= O_NONBLOCK;
166        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
167		err(1, "fcntl(%d, T_SETFL, %d)", fd, flags);
168
169	for (i = 0; i < N; i++)
170		add(i, -1);
171
172	kill(getppid(), SIGHUP);
173	while (access("work", R_OK) == 0)
174		usleep(100);
175
176	_exit(0);
177}
178
179int
180main(void)
181{
182	off_t len;
183	long val, sum;
184	int flags, i;
185
186	signal(SIGHUP, handler);
187	signal(SIGALRM, ahandler);
188	alarm(300);
189	if ((fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
190		err(1, "open(%s)", name);
191	len = N * sizeof(val);
192	if (ftruncate(fd, len) == -1)
193		err(1, "ftruncate");
194
195        if ((flags = fcntl(fd, F_GETFL)) == -1)
196		err(1, "fcntl(%d, T_GETFL)", fd);
197        flags |= O_NONBLOCK;
198        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
199		err(1, "fcntl(%d, T_SETFL, %d)", fd, flags);
200
201	for (i = 0; i < PARALLEL; i++) {
202		if (fork() == 0)
203			up();
204	}
205	for (i = 0; i < PARALLEL; i++) {
206		if (fork() == 0)
207			down();
208	}
209
210	while (completed != PARALLEL * 2)
211		usleep(200);
212
213	if (lseek(fd, 0, SEEK_SET) == -1)
214		err(1, "lseek");
215	sum = 0;
216	for (i = 0; i < N; i++) {
217		if (read(fd, &val, sizeof(val)) != sizeof(val))
218			err(1, "Final read");
219		if (val != 0)
220			fprintf(stderr, "index %d: %ld\n", i, val);
221		sum += val;
222	}
223	if (sum != 0)
224		fprintf(stderr, "FAIL\n");
225	unlink(name);
226
227	for (i = 0; i < PARALLEL; i++) {
228		wait(NULL);
229		wait(NULL);
230	}
231
232	close(fd);
233
234	return (sum != 0);
235}
236