Re: [PATCH v9 1/2] fsstress: add mwrite/mread into test operation list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 28, 2017 at 04:46:34PM +0800, Zorro Lang wrote:
> mmap as a popular and basic operation, most of softwares use it to
> access files. More and more customers report bugs related with
> mmap/munmap and other stress conditions.
> 
> So add mmap read/write test into fsstress to increase mmap related
> stress to reproduce or find more bugs easily.
> 
> Signed-off-by: Zorro Lang <zlang@xxxxxxxxxx>
> ---

Hi,

Sorry I forgot to write changelog.

Thanks Eryu found a problem by run g/270 and give me more suggestions.
When filesystem is filled, mwrite a hole of sparse file will hit
ENOSPC, and will trigger SIGBUS which will kill running process and
core dump.

So V9 add SIGBUS handler. Use sigsetjmp() before mwrite a mapped
memory, and siglongjmp() back to sigsetjmp() place from signal
handler. If siglongjmp() from a non-zero, print "Bus error".

To stop SIGBUS from other functions cause a endless loop (trigger
SIGBUS over and over ...), abort() the process if an unknown
SIGBUS is triggered.

generic/270 and xfs/068 test passed by merge this V9 patchset.

Thanks,
Zorro


>  configure.ac   |   1 +
>  ltp/fsstress.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  src/global.h   |   4 ++
>  3 files changed, 162 insertions(+), 2 deletions(-)
> 
> diff --git a/configure.ac b/configure.ac
> index fa48d2f..246f92e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -32,6 +32,7 @@ AC_HEADER_STDC
>  			xfs/platform_defs.h	\
>  			btrfs/ioctl.h		\
>  			cifs/ioctl.h		\
> +			sys/mman.h		\
>      ])
>  
>  AC_CHECK_HEADERS([xfs/xfs_log_format.h],,,[
> diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> index 7e7cf60..6d8f117 100644
> --- a/ltp/fsstress.c
> +++ b/ltp/fsstress.c
> @@ -17,6 +17,7 @@
>   */
>  
>  #include <linux/fs.h>
> +#include <setjmp.h>
>  #include "global.h"
>  
>  #ifdef HAVE_ATTR_XATTR_H
> @@ -69,6 +70,8 @@ typedef enum {
>  	OP_LINK,
>  	OP_MKDIR,
>  	OP_MKNOD,
> +	OP_MREAD,
> +	OP_MWRITE,
>  	OP_PUNCH,
>  	OP_ZERO,
>  	OP_COLLAPSE,
> @@ -168,6 +171,8 @@ void	getdents_f(int, long);
>  void	link_f(int, long);
>  void	mkdir_f(int, long);
>  void	mknod_f(int, long);
> +void	mread_f(int, long);
> +void	mwrite_f(int, long);
>  void	punch_f(int, long);
>  void	zero_f(int, long);
>  void	collapse_f(int, long);
> @@ -208,6 +213,8 @@ opdesc_t	ops[] = {
>  	{ OP_LINK, "link", link_f, 1, 1 },
>  	{ OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
>  	{ OP_MKNOD, "mknod", mknod_f, 2, 1 },
> +	{ OP_MREAD, "mread", mread_f, 2, 0 },
> +	{ OP_MWRITE, "mwrite", mwrite_f, 2, 1 },
>  	{ OP_PUNCH, "punch", punch_f, 1, 1 },
>  	{ OP_ZERO, "zero", zero_f, 1, 1 },
>  	{ OP_COLLAPSE, "collapse", collapse_f, 1, 1 },
> @@ -262,6 +269,7 @@ int		cleanup = 0;
>  int		verbose = 0;
>  int		verifiable_log = 0;
>  sig_atomic_t	should_stop = 0;
> +sigjmp_buf	*sigbus_jmp = NULL;
>  char		*execute_cmd = NULL;
>  int		execute_freq = 1;
>  struct print_string	flag_str = {0};
> @@ -311,7 +319,26 @@ void	zero_freq(void);
>  
>  void sg_handler(int signum)
>  {
> -	should_stop = 1;
> +	switch (signum) {
> +	case SIGTERM:
> +		should_stop = 1;
> +		break;
> +	case SIGBUS:
> +		/*
> +		 * Only handle SIGBUS when mmap write to a hole and no
> +		 * block can be allocated due to ENOSPC, abort otherwise.
> +		 */
> +		if (sigbus_jmp) {
> +			siglongjmp(*sigbus_jmp, -1);
> +		} else {
> +			printf("Unknown SIGBUS is caught, Abort!\n");
> +			abort();
> +		}
> +		/* should not reach here */
> +		break;
> +	default:
> +		break;
> +	}
>  }
>  
>  int main(int argc, char **argv)
> @@ -527,10 +554,13 @@ int main(int argc, char **argv)
>  
>  	for (i = 0; i < nproc; i++) {
>  		if (fork() == 0) {
> -			action.sa_handler = SIG_DFL;
>  			sigemptyset(&action.sa_mask);
> +			action.sa_handler = SIG_DFL;
>  			if (sigaction(SIGTERM, &action, 0))
>  				return 1;
> +			action.sa_handler = sg_handler;
> +			if (sigaction(SIGBUS, &action, 0))
> +				return 1;
>  #ifdef HAVE_SYS_PRCTL_H
>  			prctl(PR_SET_PDEATHSIG, SIGKILL);
>  			if (getppid() == 1) /* parent died already? */
> @@ -2655,6 +2685,131 @@ mknod_f(int opno, long r)
>  	free_pathname(&f);
>  }
>  
> +#ifdef HAVE_SYS_MMAN_H
> +struct print_flags mmap_flags[] = {
> +	{ MAP_SHARED, "SHARED"},
> +	{ MAP_PRIVATE, "PRIVATE"},
> +	{ -1, NULL}
> +};
> +
> +#define translate_mmap_flags(flags)	  \
> +	({translate_flags(flags, "|", mmap_flags);})
> +#endif
> +
> +void
> +do_mmap(int opno, long r, int prot)
> +{
> +#ifdef HAVE_SYS_MMAN_H
> +	char		*addr;
> +	int		e;
> +	pathname_t	f;
> +	int		fd;
> +	size_t		len;
> +	__int64_t	lr;
> +	off64_t		off;
> +	int		flags;
> +	struct stat64	stb;
> +	int		v;
> +	char		st[1024];
> +	sigjmp_buf	sigbus_jmpbuf;
> +
> +	init_pathname(&f);
> +	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
> +		if (v)
> +			printf("%d/%d: do_mmap - no filename\n", procid, opno);
> +		free_pathname(&f);
> +		return;
> +	}
> +	fd = open_path(&f, O_RDWR);
> +	e = fd < 0 ? errno : 0;
> +	check_cwd();
> +	if (fd < 0) {
> +		if (v)
> +			printf("%d/%d: do_mmap - open %s failed %d\n",
> +			       procid, opno, f.path, e);
> +		free_pathname(&f);
> +		return;
> +	}
> +	if (fstat64(fd, &stb) < 0) {
> +		if (v)
> +			printf("%d/%d: do_mmap - fstat64 %s failed %d\n",
> +			       procid, opno, f.path, errno);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +	inode_info(st, sizeof(st), &stb, v);
> +	if (stb.st_size == 0) {
> +		if (v)
> +			printf("%d/%d: do_mmap - %s%s zero size\n", procid, opno,
> +			       f.path, st);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +
> +	lr = ((__int64_t)random() << 32) + random();
> +	off = (off64_t)(lr % stb.st_size);
> +	off &= (off64_t)(~(sysconf(_SC_PAGE_SIZE) - 1));
> +	len = (size_t)(random() % MIN(stb.st_size - off, FILELEN_MAX)) + 1;
> +
> +	flags = (random() % 2) ? MAP_SHARED : MAP_PRIVATE;
> +	addr = mmap(NULL, len, prot, flags, fd, off);
> +	e = (addr == MAP_FAILED) ? errno : 0;
> +	if (e) {
> +		if (v)
> +			printf("%d/%d: do_mmap - mmap failed %s%s [%lld,%d,%s] %d\n",
> +			       procid, opno, f.path, st, (long long)off,
> +			       (int)len, translate_mmap_flags(flags), e);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +
> +	if (prot & PROT_WRITE) {
> +		if ((e = sigsetjmp(sigbus_jmpbuf, 1)) == 0) {
> +			sigbus_jmp = &sigbus_jmpbuf;
> +			memset(addr, nameseq & 0xff, len);
> +		}
> +	} else {
> +		char *buf;
> +		if ((buf = malloc(len)) != NULL) {
> +			memcpy(buf, addr, len);
> +			free(buf);
> +		}
> +	}
> +	munmap(addr, len);
> +	/* set NULL to stop other functions from doing siglongjmp */
> +	sigbus_jmp = NULL;
> +
> +	if (v)
> +		printf("%d/%d: %s %s%s [%lld,%d,%s] %s\n",
> +		       procid, opno, (prot & PROT_WRITE) ? "mwrite" : "mread",
> +		       f.path, st, (long long)off, (int)len,
> +		       translate_mmap_flags(flags),
> +		       (e == 0) ? "0" : "Bus error");
> +
> +	free_pathname(&f);
> +	close(fd);
> +#endif
> +}
> +
> +void
> +mread_f(int opno, long r)
> +{
> +#ifdef HAVE_SYS_MMAN_H
> +	do_mmap(opno, r, PROT_READ);
> +#endif
> +}
> +
> +void
> +mwrite_f(int opno, long r)
> +{
> +#ifdef HAVE_SYS_MMAN_H
> +	do_mmap(opno, r, PROT_WRITE);
> +#endif
> +}
> +
>  void
>  punch_f(int opno, long r)
>  {
> diff --git a/src/global.h b/src/global.h
> index f63246b..3920c0d 100644
> --- a/src/global.h
> +++ b/src/global.h
> @@ -178,4 +178,8 @@
>  
>  #endif /* HAVE_LINUX_FALLOC_H */
>  
> +#ifdef HAVE_SYS_MMAN_H
> +#include <sys/mman.h>
> +#endif
> +
>  #endif /* GLOBAL_H */
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe fstests" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux