xref: /aosp_15_r20/external/ltp/testcases/network/nfs/nfs_stress/nfs05_make_tree.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
4  * Copyright (c) International Business Machines Corp., 2001
5  *
6  * This program is designed to stress the NFS implimentation. Many bugs were
7  * uncovered in the AIX operating system implimentation of NFS when AIX kernel
8  * was built over NFS. Source directory on a remote machine (one server many
9  * clients) NFS-mounted on to a directory on a local machine from which the
10  * kernel build was initiated. Apparently many defects/bugs were uncovered when
11  * multiple users tried to build the kernel by NFS mounting the kernel source
12  * from a remote machine and tried to build the kernel on a local machine.
13  *
14  * The test's aimed to stress NFS client/server and recreates such a senario.
15  * Spawn N number of threads. Each thread does the following:
16  *   * create a directory tree;
17  *   * populate it with ".c" files and makefiles;
18  *     hostname.1234
19  *             | - 1234.0.0.c
20  *             | - ..........
21  *             | - makefile
22  *             |_ 1234.0
23  *                    |
24  *                    | - 1234.1.0.c
25  *                    | - ..........
26  *                    | - makefile
27  *                    |_ 1234.1
28  *                           |....
29  *
30  *   * initate a build, executable will print hello world;
31  *   * clean up all the executables that were created;
32  *   * recurssively remove each subdir and its contents.
33  */
34 
35 #define _GNU_SOURCE
36 #include <stdio.h>
37 #include <sys/stat.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <pthread.h>
44 #include <sys/mount.h>
45 #include <linux/limits.h>
46 #include <errno.h>
47 #include <linux/unistd.h>
48 
49 #include "tst_safe_pthread.h"
50 #include "tst_safe_stdio.h"
51 #include "tst_test.h"
52 
53 #define gettid() syscall(__NR_gettid)
54 
55 static int thrd_num = 8;
56 static int dirs_num = 100;
57 static int file_num = 100;
58 
59 static char *t_arg, *d_arg, *f_arg;
60 
61 static struct tst_option opts[] = {
62 	{"t:", &t_arg, "Number of threads to generate, default: 8"},
63 	{"d:", &d_arg, "Number of subdirs to generate, default: 100"},
64 	{"f:", &f_arg, "Number of c files in each dir, default: 100"},
65 	{}
66 };
67 
run_targets(const char * dirname,char * cfile,pid_t tid)68 static void run_targets(const char *dirname, char *cfile, pid_t tid)
69 {
70 	int i, k, fd;
71 	char subdir[PATH_MAX] = {0};
72 	char *output_file;
73 	char buf[11];
74 	const char *const cmd_run[] = {cfile, NULL};
75 
76 	SAFE_ASPRINTF(&output_file, "%s/cmd.out", dirname);
77 
78 	/* run each binary */
79 	for (i = 0; i < dirs_num; ++i) {
80 		for (k = 0; k < file_num; ++k) {
81 			snprintf(cfile, PATH_MAX, "%s%s/%d.%d.%d",
82 				 dirname, subdir, tid, i, k);
83 
84 			tst_cmd(cmd_run, output_file, NULL, 0);
85 
86 			fd = SAFE_OPEN(output_file, O_RDONLY);
87 			SAFE_READ(1, fd, buf, 11);
88 			if (strncmp(buf, "hello world", 11))
89 				tst_brk(TFAIL, "command printed wrong message");
90 			SAFE_CLOSE(fd);
91 		}
92 		strcat(subdir, "/dir");
93 	}
94 
95 	free(output_file);
96 }
97 
thread_fn(LTP_ATTRIBUTE_UNUSED void * args)98 static void *thread_fn(LTP_ATTRIBUTE_UNUSED void *args)
99 {
100 	const char prog_buf[] = "#include <stdio.h>\n"
101 				"int main(void)\n{\n"
102 				"\tprintf(\"hello world\");\n"
103 				"\treturn 0;\n}\n";
104 
105 	const char make_buf_n[] = "CFLAGS := -O -w -g\n"
106 				  "SRCS=$(sort $(wildcard *.c))\n"
107 				  "TARGETS=$(SRCS:.c=)\n"
108 				  "all: $(TARGETS)\n"
109 				  "$(TARGETS): %: %.c\n"
110 				  "\t$(CC) -o $@ $<\n"
111 				  "clean:\n\trm -f $(TARGETS)\n"
112 				  ".PHONY: all clean\n";
113 
114 	const char make_buf[] = "CFLAGS := -O -w -g\n"
115 				"SUBDIR = dir\n"
116 				"SRCS=$(sort $(wildcard *.c))\n"
117 				"TARGETS=$(SRCS:.c=)\n"
118 				"all: $(SUBDIR) $(TARGETS)\n"
119 				"$(TARGETS): %: %.c\n"
120 				"\t$(CC) -o $@ $<\n"
121 				"$(SUBDIR):\n\t$(MAKE) -C $@\n"
122 				"clean:\n"
123 				"\trm -f $(TARGETS)\n"
124 				"\t$(MAKE) -C $(SUBDIR) clean\n"
125 				".PHONY: all $(SUBDIR) clean\n";
126 
127 	int i, k, fd, dirfd, ret;
128 	char *dirname;
129 	char cfile[PATH_MAX];
130 	char hostname[256];
131 	pid_t tid = gettid();
132 
133 	SAFE_GETHOSTNAME(hostname, 256);
134 	SAFE_ASPRINTF(&dirname, "%s.%ld", hostname, tid);
135 
136 	SAFE_MKDIR(dirname, 0755);
137 	dirfd = SAFE_OPEN(dirname, O_DIRECTORY);
138 
139 	for (i = 0; i < dirs_num; ++i) {
140 
141 		fd = openat(dirfd, "makefile", O_CREAT | O_RDWR,
142 			    S_IRWXU | S_IRWXG | S_IRWXO);
143 		if (fd < 0)
144 			tst_brk(TFAIL | TERRNO, "openat(makefile) failed");
145 
146 		if (i == dirs_num - 1)
147 			SAFE_WRITE(SAFE_WRITE_ALL, fd, make_buf_n, sizeof(make_buf_n) - 1);
148 		else
149 			SAFE_WRITE(SAFE_WRITE_ALL, fd, make_buf, sizeof(make_buf) - 1);
150 
151 		SAFE_CLOSE(fd);
152 
153 		for (k = 0; k < file_num; ++k) {
154 			snprintf(cfile, PATH_MAX, "%d.%d.%d.c", tid, i, k);
155 			fd = openat(dirfd, cfile, O_CREAT | O_RDWR,
156 				    S_IRWXU | S_IRWXG | S_IRWXO);
157 			if (fd < 0) {
158 				tst_brk(TFAIL | TERRNO,
159 					"openat(%s) failed", cfile);
160 			}
161 
162 			SAFE_WRITE(SAFE_WRITE_ALL, fd, prog_buf, sizeof(prog_buf) - 1);
163 			SAFE_CLOSE(fd);
164 		}
165 
166 		if (i == dirs_num - 1)
167 			break;
168 
169 		ret = mkdirat(dirfd, "dir", 0755);
170 		if (ret < 0)
171 			tst_brk(TFAIL | TERRNO, "mkdirat('dir') failed");
172 		dirfd = openat(dirfd, "dir", O_DIRECTORY);
173 		if (dirfd < 0)
174 			tst_brk(TFAIL | TERRNO, "openat('dir') failed");
175 	}
176 
177 	const char *const cmd_make[] = {"make", "-s", "-C", dirname, NULL};
178 	const char *const cmd_make_clean[] = {
179 		"make", "-C", dirname, "-s", "clean", NULL};
180 
181 	tst_cmd(cmd_make, NULL, NULL, 0);
182 
183 	run_targets(dirname, cfile, tid);
184 
185 	tst_cmd(cmd_make_clean, NULL, NULL, 0);
186 
187 	free(dirname);
188 
189 	return NULL;
190 }
191 
setup(void)192 static void setup(void)
193 {
194 	thrd_num = atoi(t_arg);
195 	dirs_num = atoi(d_arg);
196 	file_num = atoi(f_arg);
197 }
198 
do_test(void)199 static void do_test(void)
200 {
201 	int i;
202 	pthread_t id[thrd_num];
203 
204 	for (i = 0; i < thrd_num; ++i)
205 		SAFE_PTHREAD_CREATE(id + i, NULL, thread_fn, NULL);
206 
207 	for (i = 0; i < thrd_num; ++i)
208 		SAFE_PTHREAD_JOIN(id[i], NULL);
209 
210 	tst_res(TPASS, "'make' successfully build and clean all targets");
211 }
212 
213 static struct tst_test test = {
214 	.options = opts,
215 	.test_all = do_test,
216 	.setup = setup,
217 	.max_runtime = 300,
218 };
219