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