xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*
29  * Copyright (c) 2012 by Delphix. All rights reserved.
30  */
31 
32 /*
33  * --------------------------------------------------------------------
34  * The purpose of this test is to see if the bug reported (#4723351) for
35  * UFS exists when using a ZFS file system.
36  * --------------------------------------------------------------------
37  *
38  */
39 #define	_REENTRANT 1
40 #include <stdio.h>
41 #include <fcntl.h>
42 #include <pthread.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 
50 static char *filebase;
51 
52 static int
pickidx(void)53 pickidx(void)
54 {
55 	return (random() % 1000);
56 }
57 
58 static void *
mover(void * a)59 mover(void *a)
60 {
61 	(void) a;
62 	char buf[256];
63 	int idx, len, ret;
64 
65 	len = strlen(filebase) + 5;
66 
67 	for (;;) {
68 		idx = pickidx();
69 		(void) snprintf(buf, len, "%s.%03d", filebase, idx);
70 		ret = rename(filebase, buf);
71 		if (ret < 0 && errno != ENOENT)
72 			(void) perror("renaming file");
73 	}
74 
75 	return (NULL);
76 }
77 
78 static void *
cleaner(void * a)79 cleaner(void *a)
80 {
81 	(void) a;
82 	char buf[256];
83 	int idx, len, ret;
84 
85 	len = strlen(filebase) + 5;
86 
87 	for (;;) {
88 		idx = pickidx();
89 		(void) snprintf(buf, len, "%s.%03d", filebase, idx);
90 		ret = remove(buf);
91 		if (ret < 0 && errno != ENOENT)
92 			(void) perror("removing file");
93 	}
94 
95 	return (NULL);
96 }
97 
98 static void *
writer(void * a)99 writer(void *a)
100 {
101 	int *fd = (int *)a;
102 	int ret;
103 
104 	for (;;) {
105 		if (*fd != -1)
106 			(void) close (*fd);
107 
108 		*fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
109 		if (*fd == -1) {
110 			perror("fail to open test file, refreshing it");
111 			continue;
112 		}
113 
114 		ret = write(*fd, "test\n", 5);
115 		if (ret != 5)
116 			perror("writing file");
117 	}
118 
119 	return (NULL);
120 }
121 
122 int
main(int argc,char ** argv)123 main(int argc, char **argv)
124 {
125 	int fd;
126 	pthread_t tid;
127 
128 	if (argc == 1) {
129 		(void) printf("Usage: %s <filebase>\n", argv[0]);
130 		exit(-1);
131 	}
132 
133 	filebase = argv[1];
134 	fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
135 	if (fd < 0) {
136 		perror("creating test file");
137 		exit(-1);
138 	}
139 
140 	(void) pthread_setconcurrency(4);	/* 3 threads + main */
141 	(void) pthread_create(&tid, NULL, mover, NULL);
142 	(void) pthread_create(&tid, NULL, cleaner, NULL);
143 	(void) pthread_create(&tid, NULL, writer, (void *) &fd);
144 
145 	for (;;) {
146 		int ret;
147 		struct stat st;
148 
149 		ret = stat(filebase, &st);
150 		if (ret == 0 && (st.st_nlink > 2 || st.st_nlink < 1)) {
151 			(void) printf("st.st_nlink = %d, exiting\n", \
152 			    (int)st.st_nlink);
153 			exit(0);
154 		}
155 		(void) sleep(1);
156 	}
157 
158 	return (0);
159 }
160