[LTP] [PATCH 2/2] nfs05: rewrite the test, make use of new library

Cyril Hrubis chrubis@suse.cz
Wed Jun 22 14:30:17 CEST 2016


Hi!
> --- a/testcases/network/nfs/nfs_stress/Makefile
> +++ b/testcases/network/nfs/nfs_stress/Makefile
> @@ -19,7 +19,7 @@ top_srcdir		?= ../../../..
>  include $(top_srcdir)/include/mk/env_pre.mk
>  
>  nfs04_create_file: CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
> -nfs05_make_tree: LDLIBS += -lpthread
> +nfs05_make_tree: LDLIBS += -I../../../kernel/include -lltp -lpthread

Hmm, shouldn't we rather include testcase.mk to get the -lltp and
the include path?

And even if we don't the -I directive should go to CPPFLAGS instead.

>  INSTALL_TARGETS		:= nfs_lib.sh \
>  			   nfs01 \
> diff --git a/testcases/network/nfs/nfs_stress/nfs05 b/testcases/network/nfs/nfs_stress/nfs05
> index 0e15c8c..26977ab 100755
> --- a/testcases/network/nfs/nfs_stress/nfs05
> +++ b/testcases/network/nfs/nfs_stress/nfs05
> @@ -34,8 +34,12 @@ THREAD_NUM=${THREAD_NUM:-"8"}
>  nfs_setup

Shouldn't we check that make and gcc is installed at this point?

>  tst_resm TINFO "start nfs05_make_tree -d $DIR_NUM -f $FILE_NUM -t $THREAD_NUM"
> -ROD nfs05_make_tree -d $DIR_NUM -f $FILE_NUM -t $THREAD_NUM
> +TMPDIR=$(pwd) nfs05_make_tree -d $DIR_NUM -f $FILE_NUM -t $THREAD_NUM
>  
> -tst_resm TPASS "test finished"
> +if [ $? -ne 0 ]; then
> +	tst_resm TFAIL "'make' test failed"
> +else
> +	tst_resm TPASS "'make' test finished"
> +fi
>  
>  tst_exit
> diff --git a/testcases/network/nfs/nfs_stress/nfs05_make_tree.c b/testcases/network/nfs/nfs_stress/nfs05_make_tree.c
> index 4163988..5d128dd 100644
> --- a/testcases/network/nfs/nfs_stress/nfs05_make_tree.c
> +++ b/testcases/network/nfs/nfs_stress/nfs05_make_tree.c
> @@ -1,179 +1,50 @@
> -/******************************************************************************/
> -/*									      */
> -/* Copyright (c) International Business Machines  Corp., 2001		      */
> -/*									      */
> -/* This program is free software;  you can redistribute it and/or modify      */
> -/* it under the terms of the GNU General Public License as published by       */
> -/* the Free Software Foundation; either version 2 of the License, or          */
> -/* (at your option) any later version.					      */
> -/*									      */
> -/* This program is distributed in the hope that it will be useful,	      */
> -/* but WITHOUT ANY WARRANTY;  without even the implied warranty of	      */
> -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See	              */
> -/* the GNU General Public License for more details.			      */
> -/*									      */
> -/* You should have received a copy of the GNU General Public License	      */
> -/* along with this program;  if not, write to the Free Software		      */
> -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
> -/*									      */
> -/******************************************************************************/
> -
> -/******************************************************************************/
> -/*                                                                            */
> -/* History:     Oct - 10 - 2001 Created - Manoj Iyer, IBM Austin TX.          */
> -/*                               email:manjo@austin.ibm.com                   */
> -/*					- create a directory tree that is     */
> -/*				unique to each process. The base directory    */
> -/*				looks like hostname.<pid of the process>      */
> -/*				the subdirectories will be <pid>.0 <pid.1> etc*/
> -/*				eg:					      */
> -/*				    hostname.1234			      */
> -/*					       |_ 1234.0	              */
> -/*					               |_ 1234.1              */
> -/*					                      |_1234.2        */
> -/*								    |....     */
> -/*				hostname -  hostname of the machine           */
> -/*			        1234     -  pid of the current process.       */
> -/*			        Each of these directories are populated with  */
> -/*				N number of ".c" files and a makefile that can*/
> -/*				compile the ".c" files and also initiate      */
> -/*				compile of ".c" files in the subdirectories   */
> -/*				under it.			              */
> -/*                                                                            */
> -/*		Oct - 11 - 2001 Modified 				      */
> -/*				- fixed a bug in the makefiles, the last make-*/
> -/*				  file was expecting subdirectories. Added    */
> -/*				  code to generate a different makefile for   */
> -/*				  the last subdirectory.		      */
> -/*				- Added logic to first compile all the c files*/
> -/*				  and upon completion remove them.            */
> -/*			        - Added multithreading, arguments handling.   */
> -/*				  By default the program will generate 8      */
> -/*				  threads, each creating by default 100 deep  */
> -/*				  directory tree each containing default 100  */
> -/*			          ".c" files and one makefile.                */
> -/*			        - Added usage message.                        */
> -/*								              */
> -/*		Oct - 12 - 2001 Modified			              */
> -/*				- Added logic to print missing arguments to   */
> -/*				  options.                                    */
> -/*                                                                            */
> -/*		Oct - 15 - 2001 Modified			              */
> -/*				- Added logic to remove the files, makefiles  */
> -/*				  and subdirectories that were created.       */
> -/*			        - Added logic to print debug messages.        */
> -/*								              */
> -/*		Oct - 16 - 2001 Modified		                      */
> -/*				- Added sync() calls to commit changes.       */
> -/*				- Fixed bug. pthread_join() returns 0 when    */
> -/*			          pthread_join fails, if the thread function  */
> -/*				  fails pthread_join() will put the exit value*/
> -/*			          of the thread function in the thread_return */
> -/*				  output argument.			      */
> -/*				- Debugging function crte_mk_rm fails to      */
> -/*				  create fies, problem appears only in multi- */
> -/*				  threaded case.                              */
> -/*								              */
> -/*		Oct - 17 - 2001 Checked in		                      */
> -/*				- GPL statement was added and the initial ver */
> -/*			        - checked into CVS.		              */
> -/*			        - note: this version works only if it is run  */
> -/*				  single threaded, when its run multithreaded */
> -/*		                  random thread will fail on open() sys call  */
> -/*				  problem currently under investigation.      */
> -/*                                                                            */
> -/*		Oct - 20 - 2001 Modified				      */
> -/*				- fixed a whole bunch of problems.            */
> -/*			        - created function init_compile. Apparently   */
> -/*				  this code works!!.                          */
> -/*			        - removed system() system call that was doing */
> -/*				  make and make clean. init_compile() replaces*/
> -/*				  this piece of code.                         */
> -/*				- on supplying the full pathname to unlink()  */
> -/*				  solved most of the problems with rm_file_mk */
> -/*			          function.                                   */
> -/*				- reset the default vaulues for MAXT = 8      */
> -/*				  MAXD = 100 and MAXF = 100.                  */
> -/*				  ie. maximum number of threads = 8           */
> -/*				      directory depth (num of sub dirs) = 100 */
> -/*				      numeber of .c fils in each sub dir = 100*/
> -/*				- finally program is now in working state.    */
> -/*                                                                            */
> -/*		Nov - 01 - 2001 Modified.				      */
> -/*				- fixed usage message default MAXT is 8 not 1 */
> -/*				- fixed make to compile the files silently    */
> -/*									      */
> -/*		Nov - 19 - 2001 Modified.				      */
> -/*				- changed th_status in function main() from   */
> -/*				  dynamic variable to static array.           */
> -/*									      */
> -/* File:        make_tree.c                                                   */
> -/*                                                                            */
> -/* Description:	This program is designed stress the NFS implimentation.       */
> -/* 		Many bugs were uncovered in the AIX operating system          */
> -/*		implimentation of NFS when AIX kernel was built over NFS.     */
> -/*		Source directory on a remote machine (one server many clients)*/
> -/*		NFS-mounted on to a directory on a local machine from which   */
> -/*		the kernel build was initiated. Apparently many defects/bugs  */
> -/* 		were uncovered when multiple users tried to build the kernel  */
> -/* 		by NFS mounting the kernel source from a remote machine and   */
> -/* 		tried to build the kernel on a local machine. AIX build envi- */
> -/*		ronment is set up to create the object files and executable   */
> -/*		on the local machine. 					      */
> -/* 		This testcase will try to recreate such a senario.            */
> -/*		Spawn N number of threads. Each thread does the following.    */
> -/*		* Create a directory tree.                                    */
> -/*		* Populate it with ".c" files and makefiles.                  */
> -/*		* initate a build. Executable will print hello world when exed*/
> -/*		* clean up all the executables that were created.             */
> -/*		* recurssively remove each subdir and its contents.           */
> -/*		The test is aimed at stressing the NFS client and server.     */
> -/*				    hostname.1234			      */
> -/*                                             |                              */
> -/*				               | - 1234.0.0.c                 */
> -/*					       | - 1234.0.1.c                 */
> -/*                                             | - ..........                 */
> -/*					       | - makefile                   */
> -/*                                             |                              */
> -/*					       |_ 1234.0	              */
> -/*                                                    |                       */
> -/*				                      | - 1234.1.0.c          */
> -/*					              | - 1234.1.1.c          */
> -/*                                                    | - ..........          */
> -/*					              | - makefile            */
> -/*                                                    |                       */
> -/*					              |_ 1234.1               */
> -/*                                                           |                */
> -/*				                             | - 1234.2.0.c   */
> -/*					                     | - 1234.2.1.c   */
> -/*                                                           | - ..........   */
> -/*					                     | - makefile     */
> -/*                                                           |                */
> -/*					                     |_1234.2         */
> -/*								    |....     */
> -/*                                                                            */
> -/* Setup:	- on the server side:			                      */
> -/*		  * create a directory /nfs_test 		              */
> -/*		  * make an entry in /etc/exports file like this...           */
> -/*		    "/nfs_test *(rw,no_root_squash)"		              */
> -/*		  * run command "exportfs -a"		                      */
> -/*	        - on client side:			                      */
> -/*		  * create a directory say for eg: /nfs_cli                   */
> -/*		  * mount -t nfs servername:/nfs_test /nfs_cli                */
> -/*		  * set up the tescase in /nfs_cli directory		      */
> -/*		- I reccomend that you have atleast 8 client machines running */
> -/*		   this test, linux has 8 NFSD's running by default, you might*/
> -/*		   have to increase it as per your requirement.               */
> -/*		                                                              */
> -/* Note:	- assumed that NFS services are installed and configured      */
> -/*		- you have atleast 2 machines to act as client and server     */
> -/*		  (you can have muiltiple client machines and one server)     */
> -/*		- large amount of disk space, this depends on the number of   */
> -/*		  of clients you will have, if you have only one client, I    */
> -/*		  reccomend that the server have atleast 4 Giga bytes of      */
> -/*		  disk space (paranoid!).			              */
> -/*									      */
> -/******************************************************************************/
> +/*
> + * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
> + * Copyright (c) International Business Machines  Corp., 2001
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> + * Description:
> + * This program is designed to stress the NFS implimentation. Many bugs were
> + * uncovered in the AIX operating system implimentation of NFS when AIX kernel
> + * was built over NFS. Source directory on a remote machine (one server many
> + * clients) NFS-mounted on to a directory on a local machine from which the
> + * kernel build was initiated. Apparently many defects/bugs were uncovered when
> + * multiple users tried to build the kernel by NFS mounting the kernel source
> + * from a remote machine and tried to build the kernel on a local machine.
> + *
> + * The test's aimed to stress NFS client/server and recreates such a senario.
> + * Spawn N number of threads. Each thread does the following:
> + *   * create a directory tree;
> + *   * populate it with ".c" files and makefiles;
> + *     hostname.1234
> + *             | - 1234.0.0.c
> + *             | - ..........
> + *             | - makefile
> + *             |_ 1234.0
> + *                    |
> + *                    | - 1234.1.0.c
> + *                    | - ..........
> + *                    | - makefile
> + *                    |_ 1234.1
> + *                           |....
> + *
> + *   * initate a build, executable will print hello world;
> + *   * clean up all the executables that were created;
> + *   * recurssively remove each subdir and its contents.
> + *
> + */
>  
>  #include <stdio.h>
>  #include <sys/stat.h>
> @@ -188,609 +59,133 @@
>  #include <errno.h>
>  #include <linux/unistd.h>
>  
> -#define gettid() syscall(__NR_gettid)
> -
> -#ifdef DEBUG
> -#define dprt(fmt, args...)	printf(fmt, ## args)
> -#else
> -#define dprt(fmt, args...)
> -#endif
> -
> -#define MAKE_EXE	1	/* initate a make                             */
> -#define MAKE_CLEAN	0	/* initate a make clean                       */
> -
> -#define PTHREAD_EXIT(val)    do {\
> -			exit_val = val; \
> -                        dprt("pid[%d]: exiting with %d\n", gettid(),exit_val); \
> -			pthread_exit((void *)exit_val); \
> -				} while (0)
> -
> -#define OPT_MISSING(prog, opt)   do{\
> -			       fprintf(stderr, "%s: option -%c ", prog, opt); \
> -                               fprintf(stderr, "requires an argument\n"); \
> -                               usage(prog); \
> -                                   } while (0)
> -
> -#define MAXD	100		/* default number of directories to create.           */
> -#define MAXF	100		/* default number of files to create.                 */
> -#define MAXT	8		/* default number of threads to create.               */
> -
> -/******************************************************************************/
> -/*								 	      */
> -/* Function:	usage							      */
> -/*									      */
> -/* Description:	Print the usage message.				      */
> -/*									      */
> -/* Return:	exits with -1						      */
> -/*									      */
> -/******************************************************************************/
> -static void usage(char *progname)
> -{				/* name of this program                       */
> -	fprintf(stderr,
> -		"Usage: %s -d NUMDIR -f NUMFILES -h -t NUMTHRD\n"
> -		"\t -d Number of subdirectories to generate:   Default: 100\n"
> -		"\t -f Number of c files in each subdirectory: Default: 100\n"
> -		"\t -h Help!\n"
> -		"\t -t Number of threads to generate:          Default: 8\n",
> -		progname);
> -	exit(-1);
> -}
> -
> -/******************************************************************************/
> -/*								 	      */
> -/* Function:	init_compile						      */
> -/*									      */
> -/* Description:	This function compiles the .c files and removes the exeutables*/
> -/*		This function does the same function as the system() system   */
> -/*		call, the code is available in the system() man page. When    */
> -/*		called with the parameter MAKE_EXE it will initiate make in   */
> -/*		the first directory created, the makefile is designed to build*/
> -/*		recursively all the files in the subdirectories below.        */
> -/*		When called with the MAKE_CLEAN parameter it will remove the  */
> -/*		executables that were created design is similar to the case   */
> -/*		were it initiates a make.                                     */
> -/*									      */
> -/* Return:	exits with 1 on error, 0 on success                           */
> -/*									      */
> -/******************************************************************************/
> -static int init_compile(int what_todo,	/* do a compile or clean             */
> -			char *base_dir,	/* base directory of the test        */
> -			char *hname)
> -{				/* hostname of the machine           */
> -	int status;		/* return status of execve process            */
> -	pid_t pid;		/* pid of the process that does compile       */
> -	char *dirname;		/* location where compile is initated         */
> -	char *command;		/* make or make clean command.                */
> -
> -	if ((dirname = malloc(sizeof(char) * 2048)) == NULL) {	/* just paranoid */
> -		perror("init_compile(): dirname malloc()");
> -		return 1;
> -	}
> -
> -	if ((command = malloc(sizeof(char) * 1024)) == NULL) {	/* just paranoid */
> -		perror("init_compile(): dirname malloc()");
> -		return 1;
> -	}
> -
> -	what_todo ? sprintf(command, "make -s") : sprintf(command,
> -							  "make -s clean");
> +#include "lapi/mkdirat.h"
> +#include "tst_safe_stdio.h"
> +#include "tst_test.h"
>  
> -	sprintf(dirname, "%s/%s.%ld", base_dir, hname, gettid());
> +#define gettid() syscall(__NR_gettid)
>  
> -	if (chdir(dirname) == -1) {
> -		dprt("pid[%d]: init_compile(): dir name = %s\n", gettid(),
> -		     dirname);
> -		perror("init_compile() chdir()");
> -		free(dirname);
> -		return 1;
> -	}
> +static int thrd_num = 8;
> +static int dirs_num = 100;
> +static int file_num = 100;
>  
> -	dprt("pid[%d]: init_compile(): command = %s\n", gettid(), command);
> +static char *t_arg, *d_arg, *f_arg;
>  
> -	if ((pid = fork()) == -1) {
> -		perror("init_compile(): fork()");
> -		return 1;
> -	}
> -	if (!pid) {
> -		char *argv[4];
> +static struct tst_option opts[] = {
> +	{"t:", &t_arg, "-t x    Number of threads to generate, default: 8\n"},
> +	{"d:", &d_arg, "-d x    Number of subdirs to generate, default: 100\n"},
> +	{"f:", &f_arg, "-f x    Number of c files in each dir, default: 100\n"},
> +	{NULL, NULL, NULL}
> +};
>  
> -		argv[0] = "/bin/sh";
> -		argv[1] = "-c";
> -		argv[2] = command;
> -		argv[3] = 0;
> -
> -		if (execv("/bin/sh", argv) == -1) {
> -			perror("init_compile(): execv()");
> -			return 1;
> -		}
> -	}
> -	do {
> -		if (waitpid(pid, &status, 0) == -1) {
> -			if (errno != EINTR) {
> -				fprintf(stderr,
> -					"init_compile(): waitpid() failed\n");
> -				return 1;
> -			}
> +static void *thread_fn(LTP_ATTRIBUTE_UNUSED void *args)
> +{
> +	const char prog_buf[] = "main()\n{\n\t printf(\"hello world\");\n}\n";
> +	const size_t prog_buf_size = strlen(prog_buf);
                                     ^
				     sizeof(prog_buf) - 1
> +	int i, k, fd, dirfd, len, ret;
> +	char *dirname, *tmpdir;
> +	char cfile[PATH_MAX];
> +	char make_buf[1024];
> +	char hostname[256];
> +	pid_t tid = gettid();
> +
> +	SAFE_GETHOSTNAME(hostname, 256);
> +	SAFE_ASPRINTF(&dirname, "%s.%ld", hostname, tid);
> +	SAFE_ASPRINTF(&tmpdir, "%ld", tid);
> +
> +	SAFE_MKDIR(dirname, 0755);
> +	dirfd = SAFE_OPEN(dirname, O_DIRECTORY);
> +
> +	for (i = 0; i < dirs_num; ++i) {
> +		if (i == dirs_num - 1) {
> +			len = snprintf(make_buf, 1024,
> +				"CFLAGS := -O -w -g\n"
> +				"SUBDIRS = %s\n"
> +				"SRCS=$(wildcard *.c)\n"
> +				"TARGETS=$(patsubst %%.c,\%%,$(SRCS))\n"
> +				"all:\t $(TARGETS)\n"
> +				"clean:\n"
> +				"\trm -f $(TARGETS)\n",
> +				tmpdir);

                      The SUBDIRS variable seems to be unused here.

>  		} else {
> -			if (chdir(base_dir) == -1) {
> -				dprt("pid[%d]: init_compile(): dir = %s\n",
> -				     gettid(), dirname);
> -				perror("init_compile(): chdir()");
> -				return 1;
> +			len = snprintf(make_buf, 1024,
> +				"CFLAGS := -O -w -g\n"
> +				"SUBDIRS = %s\n"
> +				"SRCS=$(wildcard *.c)\n"
> +				"TARGETS=$(patsubst %%.c,\%%,$(SRCS))\n"
> +				"all:\t $(TARGETS)\n\t@for i in $(SUBDIRS);"
> +				"do $(MAKE) -C $$i ; done\nclean:\n"
> +				"\trm -f $(TARGETS)\n\t@for i in $(SUBDIRS);"
> +				"do $(MAKE) -C $$i clean ; done\n", tmpdir);
> +		}
> +
> +		fd = openat(dirfd, "makefile", O_CREAT | O_RDWR,
> +			    S_IRWXU | S_IRWXG | S_IRWXO);
> +		if (fd < 0)
> +			tst_brk(TFAIL | TERRNO, "openat(makefile) failed");
> +
> +		SAFE_WRITE(1, fd, make_buf, len);
> +		SAFE_CLOSE(fd);
> +
> +		for (k = 0; k < file_num; ++k) {
> +			snprintf(cfile, PATH_MAX, "%d.%d.%d.c", tid, i, k);
> +			fd = openat(dirfd, cfile, O_CREAT | O_RDWR,
> +				    S_IRWXU | S_IRWXG | S_IRWXO);
> +			if (fd < 0) {
> +				tst_brk(TFAIL | TERRNO,
> +					"openat(%s) failed", cfile);
>  			}
>  
> -			dprt("pid[%d]: init_compile(): status = %d\n",
> -			     gettid(), status);
> -			dprt("we are here %d\n", __LINE__);
> -			return status;
> +			SAFE_WRITE(1, fd, prog_buf, prog_buf_size);
> +			fsync(fd);

Why do we fsync(fd) here? Isn't the whole point of this test to find a
race conditions?

-- 
Cyril Hrubis
chrubis@suse.cz


More information about the ltp mailing list