All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
       [not found] ` <1422876702-3152-2-git-send-email-wangxg.fnst@cn.fujitsu.com>
@ 2015-02-02 16:07   ` Jan Stancek
  2015-02-03  2:04     ` Xiaoguang Wang
  2015-02-03  9:57   ` Cyril Hrubis
  1 sibling, 1 reply; 9+ messages in thread
From: Jan Stancek @ 2015-02-02 16:07 UTC (permalink / raw)
  To: Xiaoguang Wang; +Cc: ltp-list





----- Original Message -----
> From: "Xiaoguang Wang" <wangxg.fnst@cn.fujitsu.com>
> To: ltp-list@lists.sourceforge.net
> Sent: Monday, 2 February, 2015 12:31:42 PM
> Subject: [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data	corruption when blocksize < pagesize for mmaped
> data
> 
> This data corruption fixed by:
>     commit 90a8020278c1598fafd071736a0846b38510309c
>     Author: Jan Kara <jack@suse.cz>
>     Date:   Wed Oct 1 21:49:18 2014 -0400
>         vfs: fix data corruption when blocksize < pagesize for mmaped data
> 
> and this test is written to run in ext4 filesystem(with mount option
> 'nodelalloc'),
> so there is another fixing patch needed:
>     commit d6320cbfc92910a3e5f10c42d98c231c98db4f60
>     Author: Jan Kara <jack@suse.cz>
>     Date:   Wed Oct 1 21:49:46 2014 -0400
>         ext4: fix mmap data corruption when blocksize < pagesize
> 
> Signed-off-by: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>

Hi,

looks good, I ran it on patched/unpatched kernel and it recognized buggy one.
Couple small suggestions inline:

> ---
>  runtest/ltplite                         |   1 +
>  runtest/stress.part3                    |   1 +
>  runtest/syscalls                        |   1 +
>  testcases/kernel/syscalls/.gitignore    |   1 +
>  testcases/kernel/syscalls/mmap/mmap16.c | 238
>  ++++++++++++++++++++++++++++++++
>  5 files changed, 242 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/mmap/mmap16.c
> 
> diff --git a/runtest/ltplite b/runtest/ltplite
> index 1457908..5d6c815 100644
> --- a/runtest/ltplite
> +++ b/runtest/ltplite
> @@ -449,6 +449,7 @@ mmap06 mmap06
>  mmap07 mmap07
>  mmap08 mmap08
>  mmap09 mmap09
> +mmap16 mmap16
>  
>  modify_ldt01 modify_ldt01
>  modify_ldt02 modify_ldt02
> diff --git a/runtest/stress.part3 b/runtest/stress.part3
> index 368c640..9736a3f 100644
> --- a/runtest/stress.part3
> +++ b/runtest/stress.part3
> @@ -382,6 +382,7 @@ mmap06 mmap06
>  mmap07 mmap07
>  mmap08 mmap08
>  mmap09 mmap09
> +mmap16 mmap16
>  
>  modify_ldt01 modify_ldt01
>  modify_ldt02 modify_ldt02
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 44969f3..4e780d7 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -587,6 +587,7 @@ mmap14 mmap14
>  # test is broken, mask it for now.
>  #mmap11 mmap11 -i 30000
>  mmap15 mmap15
> +mmap16 mmap16
>  
>  modify_ldt01 modify_ldt01
>  modify_ldt02 modify_ldt02
> diff --git a/testcases/kernel/syscalls/.gitignore
> b/testcases/kernel/syscalls/.gitignore
> index 92c0bf5..b443fd8 100644
> --- a/testcases/kernel/syscalls/.gitignore
> +++ b/testcases/kernel/syscalls/.gitignore
> @@ -533,6 +533,7 @@
>  /mmap/mmap13
>  /mmap/mmap14
>  /mmap/mmap15
> +/mmap/mmap16
>  /modify_ldt/modify_ldt01
>  /modify_ldt/modify_ldt02
>  /modify_ldt/modify_ldt03
> diff --git a/testcases/kernel/syscalls/mmap/mmap16.c
> b/testcases/kernel/syscalls/mmap/mmap16.c
> new file mode 100644
> index 0000000..9054503
> --- /dev/null
> +++ b/testcases/kernel/syscalls/mmap/mmap16.c
> @@ -0,0 +1,238 @@
> +/*
> + *   Copyright (c) 2015 Fujitsu Ltd.
> + *   Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
> + *
> + *   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.
> + */
> +
> +/*
> + * This is a regression test for commit:
> + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
> + * commit/?id=90a8020
> + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
> + * commit/?id=d6320cb
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <sys/mount.h>
> +#include <sys/mman.h>
> +
> +#include "usctest.h"
> +#include "test.h"
> +#include "safe_macros.h"
> +
> +#define MNTPOINT	"mntpoint"
> +#define FS_BLOCKSIZE	1024
> +
> +static void setup(void);
> +static void cleanup(void);
> +static void do_child(void);
> +static void do_test(void);
> +
> +static const char *device;
> +static const char *fs_type = "ext4";
> +static int mount_flag;
> +
> +static int page_size;
> +static struct tst_checkpoint checkpoint1, checkpoint2;
> +static int bug_reproduced;
> +
> +char *TCID = "mmap16";
> +int TST_TOTAL = 1;
> +
> +int main(int ac, char **av)
> +{
> +	int i;
> +	const char *msg;
> +
> +	msg = parse_opts(ac, av, NULL, NULL);
> +	if (msg != NULL)
> +		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
> +
> +	setup();
> +
> +	/*
> +	 * If child process was killed by SIGBUS, indeed that can not guarantee
> +	 * this bug must have been fixed, If luckily virtual memory subsystem
> +	 * decides that it is time to write dirty pages, it will make maped
> +	 * pages write-protect, so ->page_mkwrite() still will be called, child
> +	 * process will be killed by SIGBUS, it's not fixed because of above
> +	 * fixing patches. So here we run this test 10 times, if once, child
> +	 * process exits normally, we can sure that this bug is not fixed.
> +	 */
> +	for (i = 0; i < 10; i++)
> +		do_test();

Would it be worth it to convert this loop to TEST_LOOPING?
Then you can add "mmap16 -i 10" to lite runtest files and for example "-i 50"
to stress one. From my runs, it reproduced quite quickly, so 50 may be overkill.


> +
> +	if (bug_reproduced)
> +		tst_resm(TFAIL, "Bug is reproduced!");
> +	else
> +		tst_resm(TPASS, "Bug is not reproduced!");
> +
> +	cleanup();
> +	tst_exit();
> +}
> +
> +static void do_test(void)
> +{
> +	int fd, ret, status;
> +	pid_t child;
> +	char buf[FS_BLOCKSIZE];
> +
> +	SAFE_TOUCH(cleanup, "testfilep", 0644, NULL);
> +	SAFE_TOUCH(cleanup, "testfilec", 0644, NULL);
> +
> +	child = tst_fork();
> +	if (child < 0) {
> +		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
> +	} else if (child == 0) {
> +		do_child();
> +	} else {
> +		fd = SAFE_OPEN(cleanup, "testfilep", O_RDWR);
> +		memset(buf, 'a', FS_BLOCKSIZE);
> +
> +		TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1);
> +		while (1) {
> +			ret = write(fd, buf, FS_BLOCKSIZE);
> +			if (ret < 0) {
> +				if (errno == ENOSPC) {
> +					break;
> +				} else {
> +					tst_brkm(TBROK | TERRNO, cleanup,
> +						 "write failed unexpectedly");
> +				}
> +			}
> +		}
> +		SAFE_CLOSE(cleanup, fd);
> +		TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2);
> +	}
> +
> +	wait(&status);
> +	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGBUS) {
> +		;
> +	} else if (WIFEXITED(status) && WEXITSTATUS(status) == 1) {
> +		bug_reproduced = 1;
> +	} else {
> +		tst_brkm(TBROK | TERRNO, cleanup,
> +			 "child process terminate unexpectedly");
> +	}
> +
> +	SAFE_UNLINK(cleanup, "testfilep");
> +	SAFE_UNLINK(cleanup, "testfilec");
> +}
> +
> +static void setup(void)
> +{
> +	const char *fs_opts[3] = {"-b", "1024", NULL};
> +

Missing tst_require_root().

> +	tst_sig(FORK, DEF_HANDLER, NULL);
> +
> +	TEST_PAUSE;
> +	tst_tmpdir();
> +
> +	page_size = getpagesize();
> +	if (page_size == -1)
> +		tst_brkm(TBROK | TERRNO, cleanup, "Unable to get page size");
> +
> +	device = tst_acquire_device(cleanup);
> +	if (!device)
> +		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
> +	tst_mkfs(cleanup, device, fs_type, fs_opts);
> +
> +	SAFE_MKDIR(cleanup, MNTPOINT, 0755);
> +	/*
> +	 * Disable ext4 delalloc feature, so block will be allocated
> +	 * as soon as possible
> +	 */
> +	if (mount(device, MNTPOINT, fs_type, 0, "nodelalloc") < 0) {
> +		tst_brkm(TBROK | TERRNO, cleanup,
> +			 "mount device:%s failed", device);
> +	}
> +	mount_flag = 1;
> +
> +	SAFE_CHDIR(cleanup, MNTPOINT);
> +	TST_CHECKPOINT_CREATE(&checkpoint1);
> +	TST_CHECKPOINT_CREATE(&checkpoint2);
> +}
> +
> +static void do_child(void)
> +{
> +	int fd, offset;
> +	char buf[FS_BLOCKSIZE];
> +	char *addr = NULL;
> +
> +	/*
> +	 * We have changed SIGBUS' handler in parent process,
> +	 * so here just restore it
> +	 */

It took me a while to realize that this happens as part of LTP library and
not in parent code.

Regards,
Jan

> +	if (signal(SIGBUS, SIG_DFL) == SIG_ERR)
> +		tst_brkm(TBROK | TERRNO, NULL, "signal(SIGBUS) failed");
> +
> +	memset(buf, 'a', FS_BLOCKSIZE);
> +	fd = SAFE_OPEN(NULL, "testfilec", O_RDWR);
> +	SAFE_PWRITE(NULL, 1, fd, buf, FS_BLOCKSIZE, 0);
> +
> +	/*
> +	 * In case mremap() may fail because that memory area can not be
> +	 * expanded at current virtual address(MREMAP_MAYMOVE is not set),
> +	 * we first do a mmap(page_size * 2) operation to reserve some
> +	 * free address space.
> +	 */
> +	addr = (char *)SAFE_MMAP(NULL, NULL, page_size * 2, PROT_WRITE |
> +				 PROT_READ, MAP_PRIVATE_EXCEPT_UCLINUX|
> +				 MAP_ANONYMOUS, -1, 0);
> +	SAFE_MUNMAP(NULL, addr,  page_size * 2);
> +
> +	addr = (char *)SAFE_MMAP(NULL, addr, FS_BLOCKSIZE, PROT_WRITE |
> +				 PROT_READ, MAP_SHARED, fd, 0);
> +
> +	addr[0] = 'a';
> +
> +	SAFE_FTRUNCATE(NULL, fd, page_size * 2);
> +	addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0);
> +	if (addr == MAP_FAILED)
> +		tst_brkm(TBROK | TERRNO, NULL, "mremap failed unexpectedly");
> +
> +	/*
> +	 * Let parent process consume FS free blocks as many as possible, then
> +	 * there'll be no free blocks allocated for this new file mmaping for
> +	 * offset starting at 1024, 2048, or 3072. If this above kernel bug
> +	 * has been fixed, usually child process will killed by SIGBUS signal,
> +	 * if not, the data 'A', 'B', 'C' will be silently discarded later when
> +	 * kernel writepage is called, that means data corruption.
> +	 */
> +	TST_CHECKPOINT_SIGNAL_PARENT(&checkpoint1);
> +	TST_CHECKPOINT_CHILD_WAIT(&checkpoint2);
> +
> +	for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE)
> +		addr[offset] = 'a';
> +	exit(TFAIL);
> +}
> +
> +static void cleanup(void)
> +{
> +	TEST_CLEANUP;
> +
> +	SAFE_CHDIR(NULL, "..");
> +	if (mount_flag && tst_umount(MNTPOINT) < 0)
> +		tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
> +
> +	if (device)
> +		tst_release_device(NULL, device);
> +
> +	tst_rmdir();
> +}
> --
> 1.8.3.1
> 
> 
> ------------------------------------------------------------------------------
> Dive into the World of Parallel Programming. The Go Parallel Website,
> sponsored by Intel and developed in partnership with Slashdot Media, is your
> hub for all things parallel software development, from weekly thought
> leadership blogs to news, videos, case studies, tutorials and more. Take a
> look and join the conversation now. http://goparallel.sourceforge.net/
> _______________________________________________
> Ltp-list mailing list
> Ltp-list@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/ltp-list
> 

------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
  2015-02-02 16:07   ` [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data Jan Stancek
@ 2015-02-03  2:04     ` Xiaoguang Wang
  0 siblings, 0 replies; 9+ messages in thread
From: Xiaoguang Wang @ 2015-02-03  2:04 UTC (permalink / raw)
  To: Jan Stancek; +Cc: ltp-list

Hi,

On 02/03/2015 12:07 AM, Jan Stancek wrote:
> 
> 
> 
> 
> ----- Original Message -----
>> From: "Xiaoguang Wang" <wangxg.fnst@cn.fujitsu.com>
>> To: ltp-list@lists.sourceforge.net
>> Sent: Monday, 2 February, 2015 12:31:42 PM
>> Subject: [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data	corruption when blocksize < pagesize for mmaped
>> data
>>
>> This data corruption fixed by:
>>     commit 90a8020278c1598fafd071736a0846b38510309c
>>     Author: Jan Kara <jack@suse.cz>
>>     Date:   Wed Oct 1 21:49:18 2014 -0400
>>         vfs: fix data corruption when blocksize < pagesize for mmaped data
>>
>> and this test is written to run in ext4 filesystem(with mount option
>> 'nodelalloc'),
>> so there is another fixing patch needed:
>>     commit d6320cbfc92910a3e5f10c42d98c231c98db4f60
>>     Author: Jan Kara <jack@suse.cz>
>>     Date:   Wed Oct 1 21:49:46 2014 -0400
>>         ext4: fix mmap data corruption when blocksize < pagesize
>>
>> Signed-off-by: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
> 
> Hi,
> 
> looks good, I ran it on patched/unpatched kernel and it recognized buggy one.
> Couple small suggestions inline:
> 
>> ---
>>  runtest/ltplite                         |   1 +
>>  runtest/stress.part3                    |   1 +
>>  runtest/syscalls                        |   1 +
>>  testcases/kernel/syscalls/.gitignore    |   1 +
>>  testcases/kernel/syscalls/mmap/mmap16.c | 238
>>  ++++++++++++++++++++++++++++++++
>>  5 files changed, 242 insertions(+)
>>  create mode 100644 testcases/kernel/syscalls/mmap/mmap16.c
>>
>> diff --git a/runtest/ltplite b/runtest/ltplite
>> index 1457908..5d6c815 100644
>> --- a/runtest/ltplite
>> +++ b/runtest/ltplite
>> @@ -449,6 +449,7 @@ mmap06 mmap06
>>  mmap07 mmap07
>>  mmap08 mmap08
>>  mmap09 mmap09
>> +mmap16 mmap16
>>  
>>  modify_ldt01 modify_ldt01
>>  modify_ldt02 modify_ldt02
>> diff --git a/runtest/stress.part3 b/runtest/stress.part3
>> index 368c640..9736a3f 100644
>> --- a/runtest/stress.part3
>> +++ b/runtest/stress.part3
>> @@ -382,6 +382,7 @@ mmap06 mmap06
>>  mmap07 mmap07
>>  mmap08 mmap08
>>  mmap09 mmap09
>> +mmap16 mmap16
>>  
>>  modify_ldt01 modify_ldt01
>>  modify_ldt02 modify_ldt02
>> diff --git a/runtest/syscalls b/runtest/syscalls
>> index 44969f3..4e780d7 100644
>> --- a/runtest/syscalls
>> +++ b/runtest/syscalls
>> @@ -587,6 +587,7 @@ mmap14 mmap14
>>  # test is broken, mask it for now.
>>  #mmap11 mmap11 -i 30000
>>  mmap15 mmap15
>> +mmap16 mmap16
>>  
>>  modify_ldt01 modify_ldt01
>>  modify_ldt02 modify_ldt02
>> diff --git a/testcases/kernel/syscalls/.gitignore
>> b/testcases/kernel/syscalls/.gitignore
>> index 92c0bf5..b443fd8 100644
>> --- a/testcases/kernel/syscalls/.gitignore
>> +++ b/testcases/kernel/syscalls/.gitignore
>> @@ -533,6 +533,7 @@
>>  /mmap/mmap13
>>  /mmap/mmap14
>>  /mmap/mmap15
>> +/mmap/mmap16
>>  /modify_ldt/modify_ldt01
>>  /modify_ldt/modify_ldt02
>>  /modify_ldt/modify_ldt03
>> diff --git a/testcases/kernel/syscalls/mmap/mmap16.c
>> b/testcases/kernel/syscalls/mmap/mmap16.c
>> new file mode 100644
>> index 0000000..9054503
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/mmap/mmap16.c
>> @@ -0,0 +1,238 @@
>> +/*
>> + *   Copyright (c) 2015 Fujitsu Ltd.
>> + *   Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
>> + *
>> + *   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.
>> + */
>> +
>> +/*
>> + * This is a regression test for commit:
>> + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
>> + * commit/?id=90a8020
>> + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
>> + * commit/?id=d6320cb
>> + */
>> +
>> +#define _GNU_SOURCE
>> +
>> +#include <stdio.h>
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <sys/types.h>
>> +#include <sys/wait.h>
>> +#include <unistd.h>
>> +#include <sys/mount.h>
>> +#include <sys/mman.h>
>> +
>> +#include "usctest.h"
>> +#include "test.h"
>> +#include "safe_macros.h"
>> +
>> +#define MNTPOINT	"mntpoint"
>> +#define FS_BLOCKSIZE	1024
>> +
>> +static void setup(void);
>> +static void cleanup(void);
>> +static void do_child(void);
>> +static void do_test(void);
>> +
>> +static const char *device;
>> +static const char *fs_type = "ext4";
>> +static int mount_flag;
>> +
>> +static int page_size;
>> +static struct tst_checkpoint checkpoint1, checkpoint2;
>> +static int bug_reproduced;
>> +
>> +char *TCID = "mmap16";
>> +int TST_TOTAL = 1;
>> +
>> +int main(int ac, char **av)
>> +{
>> +	int i;
>> +	const char *msg;
>> +
>> +	msg = parse_opts(ac, av, NULL, NULL);
>> +	if (msg != NULL)
>> +		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
>> +
>> +	setup();
>> +
>> +	/*
>> +	 * If child process was killed by SIGBUS, indeed that can not guarantee
>> +	 * this bug must have been fixed, If luckily virtual memory subsystem
>> +	 * decides that it is time to write dirty pages, it will make maped
>> +	 * pages write-protect, so ->page_mkwrite() still will be called, child
>> +	 * process will be killed by SIGBUS, it's not fixed because of above
>> +	 * fixing patches. So here we run this test 10 times, if once, child
>> +	 * process exits normally, we can sure that this bug is not fixed.
>> +	 */
>> +	for (i = 0; i < 10; i++)
>> +		do_test();
> 
> Would it be worth it to convert this loop to TEST_LOOPING?
> Then you can add "mmap16 -i 10" to lite runtest files and for example "-i 50"
> to stress one. From my runs, it reproduced quite quickly, so 50 may be overkill.

OK.
> 
> 
>> +
>> +	if (bug_reproduced)
>> +		tst_resm(TFAIL, "Bug is reproduced!");
>> +	else
>> +		tst_resm(TPASS, "Bug is not reproduced!");
>> +
>> +	cleanup();
>> +	tst_exit();
>> +}
>> +
>> +static void do_test(void)
>> +{
>> +	int fd, ret, status;
>> +	pid_t child;
>> +	char buf[FS_BLOCKSIZE];
>> +
>> +	SAFE_TOUCH(cleanup, "testfilep", 0644, NULL);
>> +	SAFE_TOUCH(cleanup, "testfilec", 0644, NULL);
>> +
>> +	child = tst_fork();
>> +	if (child < 0) {
>> +		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
>> +	} else if (child == 0) {
>> +		do_child();
>> +	} else {
>> +		fd = SAFE_OPEN(cleanup, "testfilep", O_RDWR);
>> +		memset(buf, 'a', FS_BLOCKSIZE);
>> +
>> +		TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1);
>> +		while (1) {
>> +			ret = write(fd, buf, FS_BLOCKSIZE);
>> +			if (ret < 0) {
>> +				if (errno == ENOSPC) {
>> +					break;
>> +				} else {
>> +					tst_brkm(TBROK | TERRNO, cleanup,
>> +						 "write failed unexpectedly");
>> +				}
>> +			}
>> +		}
>> +		SAFE_CLOSE(cleanup, fd);
>> +		TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2);
>> +	}
>> +
>> +	wait(&status);
>> +	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGBUS) {
>> +		;
>> +	} else if (WIFEXITED(status) && WEXITSTATUS(status) == 1) {
>> +		bug_reproduced = 1;
>> +	} else {
>> +		tst_brkm(TBROK | TERRNO, cleanup,
>> +			 "child process terminate unexpectedly");
>> +	}
>> +
>> +	SAFE_UNLINK(cleanup, "testfilep");
>> +	SAFE_UNLINK(cleanup, "testfilec");
>> +}
>> +
>> +static void setup(void)
>> +{
>> +	const char *fs_opts[3] = {"-b", "1024", NULL};
>> +
> 
> Missing tst_require_root().

Will add it.
> 
>> +	tst_sig(FORK, DEF_HANDLER, NULL);
>> +
>> +	TEST_PAUSE;
>> +	tst_tmpdir();
>> +
>> +	page_size = getpagesize();
>> +	if (page_size == -1)
>> +		tst_brkm(TBROK | TERRNO, cleanup, "Unable to get page size");
>> +
>> +	device = tst_acquire_device(cleanup);
>> +	if (!device)
>> +		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
>> +	tst_mkfs(cleanup, device, fs_type, fs_opts);
>> +
>> +	SAFE_MKDIR(cleanup, MNTPOINT, 0755);
>> +	/*
>> +	 * Disable ext4 delalloc feature, so block will be allocated
>> +	 * as soon as possible
>> +	 */
>> +	if (mount(device, MNTPOINT, fs_type, 0, "nodelalloc") < 0) {
>> +		tst_brkm(TBROK | TERRNO, cleanup,
>> +			 "mount device:%s failed", device);
>> +	}
>> +	mount_flag = 1;
>> +
>> +	SAFE_CHDIR(cleanup, MNTPOINT);
>> +	TST_CHECKPOINT_CREATE(&checkpoint1);
>> +	TST_CHECKPOINT_CREATE(&checkpoint2);
>> +}
>> +
>> +static void do_child(void)
>> +{
>> +	int fd, offset;
>> +	char buf[FS_BLOCKSIZE];
>> +	char *addr = NULL;
>> +
>> +	/*
>> +	 * We have changed SIGBUS' handler in parent process,
>> +	 * so here just restore it
>> +	 */
> 
> It took me a while to realize that this happens as part of LTP library and
> not in parent code.

Sorry, I'll add more accurate comments :)

Regards,
Xiaoguang Wang
> 
> Regards,
> Jan
> 
>> +	if (signal(SIGBUS, SIG_DFL) == SIG_ERR)
>> +		tst_brkm(TBROK | TERRNO, NULL, "signal(SIGBUS) failed");
>> +
>> +	memset(buf, 'a', FS_BLOCKSIZE);
>> +	fd = SAFE_OPEN(NULL, "testfilec", O_RDWR);
>> +	SAFE_PWRITE(NULL, 1, fd, buf, FS_BLOCKSIZE, 0);
>> +
>> +	/*
>> +	 * In case mremap() may fail because that memory area can not be
>> +	 * expanded at current virtual address(MREMAP_MAYMOVE is not set),
>> +	 * we first do a mmap(page_size * 2) operation to reserve some
>> +	 * free address space.
>> +	 */
>> +	addr = (char *)SAFE_MMAP(NULL, NULL, page_size * 2, PROT_WRITE |
>> +				 PROT_READ, MAP_PRIVATE_EXCEPT_UCLINUX|
>> +				 MAP_ANONYMOUS, -1, 0);
>> +	SAFE_MUNMAP(NULL, addr,  page_size * 2);
>> +
>> +	addr = (char *)SAFE_MMAP(NULL, addr, FS_BLOCKSIZE, PROT_WRITE |
>> +				 PROT_READ, MAP_SHARED, fd, 0);
>> +
>> +	addr[0] = 'a';
>> +
>> +	SAFE_FTRUNCATE(NULL, fd, page_size * 2);
>> +	addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0);
>> +	if (addr == MAP_FAILED)
>> +		tst_brkm(TBROK | TERRNO, NULL, "mremap failed unexpectedly");
>> +
>> +	/*
>> +	 * Let parent process consume FS free blocks as many as possible, then
>> +	 * there'll be no free blocks allocated for this new file mmaping for
>> +	 * offset starting at 1024, 2048, or 3072. If this above kernel bug
>> +	 * has been fixed, usually child process will killed by SIGBUS signal,
>> +	 * if not, the data 'A', 'B', 'C' will be silently discarded later when
>> +	 * kernel writepage is called, that means data corruption.
>> +	 */
>> +	TST_CHECKPOINT_SIGNAL_PARENT(&checkpoint1);
>> +	TST_CHECKPOINT_CHILD_WAIT(&checkpoint2);
>> +
>> +	for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE)
>> +		addr[offset] = 'a';
>> +	exit(TFAIL);
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	TEST_CLEANUP;
>> +
>> +	SAFE_CHDIR(NULL, "..");
>> +	if (mount_flag && tst_umount(MNTPOINT) < 0)
>> +		tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
>> +
>> +	if (device)
>> +		tst_release_device(NULL, device);
>> +
>> +	tst_rmdir();
>> +}
>> --
>> 1.8.3.1
>>
>>
>> ------------------------------------------------------------------------------
>> Dive into the World of Parallel Programming. The Go Parallel Website,
>> sponsored by Intel and developed in partnership with Slashdot Media, is your
>> hub for all things parallel software development, from weekly thought
>> leadership blogs to news, videos, case studies, tutorials and more. Take a
>> look and join the conversation now. http://goparallel.sourceforge.net/
>> _______________________________________________
>> Ltp-list mailing list
>> Ltp-list@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/ltp-list
>>
> .
> 


------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
       [not found] ` <1422876702-3152-2-git-send-email-wangxg.fnst@cn.fujitsu.com>
  2015-02-02 16:07   ` [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data Jan Stancek
@ 2015-02-03  9:57   ` Cyril Hrubis
  2015-02-04  8:59     ` [LTP] [PATCH v2 1/2] lib: add SAFE_PWRITE() and SAFE_PREAD() Xiaoguang Wang
  1 sibling, 1 reply; 9+ messages in thread
From: Cyril Hrubis @ 2015-02-03  9:57 UTC (permalink / raw)
  To: Xiaoguang Wang; +Cc: ltp-list

Hi!
> +/*
> + *   Copyright (c) 2015 Fujitsu Ltd.
> + *   Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
> + *
> + *   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.
> + */
> +
> +/*
> + * This is a regression test for commit:
> + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
> + * commit/?id=90a8020
> + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
> + * commit/?id=d6320cb
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <sys/mount.h>
> +#include <sys/mman.h>
> +
> +#include "usctest.h"
> +#include "test.h"
> +#include "safe_macros.h"
> +
> +#define MNTPOINT	"mntpoint"
> +#define FS_BLOCKSIZE	1024
> +
> +static void setup(void);
> +static void cleanup(void);
> +static void do_child(void);
> +static void do_test(void);
> +
> +static const char *device;
> +static const char *fs_type = "ext4";
> +static int mount_flag;
> +
> +static int page_size;
> +static struct tst_checkpoint checkpoint1, checkpoint2;
> +static int bug_reproduced;
> +
> +char *TCID = "mmap16";
> +int TST_TOTAL = 1;
> +
> +int main(int ac, char **av)
> +{
> +	int i;
> +	const char *msg;
> +
> +	msg = parse_opts(ac, av, NULL, NULL);
> +	if (msg != NULL)
> +		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
> +
> +	setup();
> +
> +	/*
> +	 * If child process was killed by SIGBUS, indeed that can not guarantee
> +	 * this bug must have been fixed, If luckily virtual memory subsystem
> +	 * decides that it is time to write dirty pages, it will make maped
> +	 * pages write-protect, so ->page_mkwrite() still will be called, child
> +	 * process will be killed by SIGBUS, it's not fixed because of above
> +	 * fixing patches. So here we run this test 10 times, if once, child
> +	 * process exits normally, we can sure that this bug is not fixed.
> +	 */
> +	for (i = 0; i < 10; i++)
> +		do_test();
> +
> +	if (bug_reproduced)
> +		tst_resm(TFAIL, "Bug is reproduced!");
> +	else
> +		tst_resm(TPASS, "Bug is not reproduced!");
> +
> +	cleanup();
> +	tst_exit();
> +}
> +
> +static void do_test(void)
> +{
> +	int fd, ret, status;
> +	pid_t child;
> +	char buf[FS_BLOCKSIZE];
> +
> +	SAFE_TOUCH(cleanup, "testfilep", 0644, NULL);
> +	SAFE_TOUCH(cleanup, "testfilec", 0644, NULL);
> +
> +	child = tst_fork();
> +	if (child < 0) {
> +		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
> +	} else if (child == 0) {
> +		do_child();
> +	} else {
> +		fd = SAFE_OPEN(cleanup, "testfilep", O_RDWR);
> +		memset(buf, 'a', FS_BLOCKSIZE);
> +
> +		TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1);
> +		while (1) {
> +			ret = write(fd, buf, FS_BLOCKSIZE);
> +			if (ret < 0) {
> +				if (errno == ENOSPC) {
> +					break;
> +				} else {
> +					tst_brkm(TBROK | TERRNO, cleanup,
> +						 "write failed unexpectedly");
> +				}
> +			}
> +		}
> +		SAFE_CLOSE(cleanup, fd);
> +		TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2);
> +	}

I tend to write this code as

	switch (child) {
	case -1:
		tst_brkm(...);
	case 0:
		do_child();
	break;
	default:
		...
	break;
	}

> +	wait(&status);
> +	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGBUS) {
> +		;

This empty body if looks strange.

Can't we just write this code as:

if (WIFEXITED(status) && WEXITSTATUS(status) == 1) {
	bug_reproduced = 1;
} else {
	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS)) {
		tst_brkm(TBROK | TERRNO, cleanup,
			 "child process terminate unexpectedly");
	}
}

Or add a TINFO message that the child has been killed with SIGBUS, so
that the body is not empty at least?

> +	} else if (WIFEXITED(status) && WEXITSTATUS(status) == 1) {
> +		bug_reproduced = 1;
> +	} else {
> +		tst_brkm(TBROK | TERRNO, cleanup,
> +			 "child process terminate unexpectedly");
> +	}
> +
> +	SAFE_UNLINK(cleanup, "testfilep");
> +	SAFE_UNLINK(cleanup, "testfilec");
> +}
> +
> +static void setup(void)
> +{
> +	const char *fs_opts[3] = {"-b", "1024", NULL};
> +
> +	tst_sig(FORK, DEF_HANDLER, NULL);
> +
> +	TEST_PAUSE;
> +	tst_tmpdir();
> +
> +	page_size = getpagesize();
> +	if (page_size == -1)
> +		tst_brkm(TBROK | TERRNO, cleanup, "Unable to get page size");
> +
> +	device = tst_acquire_device(cleanup);
> +	if (!device)
> +		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
> +	tst_mkfs(cleanup, device, fs_type, fs_opts);
> +
> +	SAFE_MKDIR(cleanup, MNTPOINT, 0755);
> +	/*
> +	 * Disable ext4 delalloc feature, so block will be allocated
> +	 * as soon as possible
> +	 */
> +	if (mount(device, MNTPOINT, fs_type, 0, "nodelalloc") < 0) {
> +		tst_brkm(TBROK | TERRNO, cleanup,
> +			 "mount device:%s failed", device);
> +	}

We do have SAFE_MOUNT() as well.

> +	mount_flag = 1;
> +
> +	SAFE_CHDIR(cleanup, MNTPOINT);
> +	TST_CHECKPOINT_CREATE(&checkpoint1);
> +	TST_CHECKPOINT_CREATE(&checkpoint2);
> +}
> +
> +static void do_child(void)
> +{
> +	int fd, offset;
> +	char buf[FS_BLOCKSIZE];
> +	char *addr = NULL;
> +
> +	/*
> +	 * We have changed SIGBUS' handler in parent process,
> +	 * so here just restore it
> +	 */
> +	if (signal(SIGBUS, SIG_DFL) == SIG_ERR)
> +		tst_brkm(TBROK | TERRNO, NULL, "signal(SIGBUS) failed");
> +
> +	memset(buf, 'a', FS_BLOCKSIZE);
> +	fd = SAFE_OPEN(NULL, "testfilec", O_RDWR);
> +	SAFE_PWRITE(NULL, 1, fd, buf, FS_BLOCKSIZE, 0);
> +
> +	/*
> +	 * In case mremap() may fail because that memory area can not be
> +	 * expanded at current virtual address(MREMAP_MAYMOVE is not set),
> +	 * we first do a mmap(page_size * 2) operation to reserve some
> +	 * free address space.
> +	 */
> +	addr = (char *)SAFE_MMAP(NULL, NULL, page_size * 2, PROT_WRITE |
> +				 PROT_READ, MAP_PRIVATE_EXCEPT_UCLINUX|
> +				 MAP_ANONYMOUS, -1, 0);

Casting void* pointers to anything else is meaningless, please don't do
that.

> +	SAFE_MUNMAP(NULL, addr,  page_size * 2);
> +
> +	addr = (char *)SAFE_MMAP(NULL, addr, FS_BLOCKSIZE, PROT_WRITE |
> +				 PROT_READ, MAP_SHARED, fd, 0);
> +
> +	addr[0] = 'a';
> +
> +	SAFE_FTRUNCATE(NULL, fd, page_size * 2);
> +	addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0);
> +	if (addr == MAP_FAILED)
> +		tst_brkm(TBROK | TERRNO, NULL, "mremap failed unexpectedly");
> +
> +	/*
> +	 * Let parent process consume FS free blocks as many as possible, then
> +	 * there'll be no free blocks allocated for this new file mmaping for
> +	 * offset starting at 1024, 2048, or 3072. If this above kernel bug
> +	 * has been fixed, usually child process will killed by SIGBUS signal,
> +	 * if not, the data 'A', 'B', 'C' will be silently discarded later when
> +	 * kernel writepage is called, that means data corruption.
> +	 */
> +	TST_CHECKPOINT_SIGNAL_PARENT(&checkpoint1);
> +	TST_CHECKPOINT_CHILD_WAIT(&checkpoint2);
> +
> +	for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE)
> +		addr[offset] = 'a';
> +	exit(TFAIL);
> +}
> +
> +static void cleanup(void)
> +{
> +	TEST_CLEANUP;
> +
> +	SAFE_CHDIR(NULL, "..");

It's better not to use SAFE_MACROS here, because we wan't to run the
rest of the cleanup even if this step fails. So what we should do here
is just:

	if (chdir(".."))
		tst_resm(TWARN | TERRNO, "chdir('..') failed");

> +	if (mount_flag && tst_umount(MNTPOINT) < 0)
> +		tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
> +
> +	if (device)
> +		tst_release_device(NULL, device);
> +
> +	tst_rmdir();
> +}
> -- 
> 1.8.3.1
> 

-- 
Cyril Hrubis
chrubis@suse.cz

------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [LTP] [PATCH v2 1/2] lib: add SAFE_PWRITE() and SAFE_PREAD()
  2015-02-03  9:57   ` Cyril Hrubis
@ 2015-02-04  8:59     ` Xiaoguang Wang
  2015-02-04  8:59       ` [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data Xiaoguang Wang
  0 siblings, 1 reply; 9+ messages in thread
From: Xiaoguang Wang @ 2015-02-04  8:59 UTC (permalink / raw)
  To: ltp-list

Signed-off-by: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
---
 include/safe_macros.h | 13 +++++++++++++
 lib/safe_macros.c     | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/include/safe_macros.h b/include/safe_macros.h
index d832d4f..ed66a0e 100644
--- a/include/safe_macros.h
+++ b/include/safe_macros.h
@@ -107,6 +107,12 @@ ssize_t	safe_read(const char *file, const int lineno,
 	safe_read(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \
 	    (buf), (nbyte))
 
+ssize_t safe_pread(const char *file, const int lineno, void (*cleanup_fn)(void),
+	    char len_strict, int fildes, void *buf, size_t nbyte, off_t offset);
+#define SAFE_PREAD(cleanup_fn, len_strict, fildes, buf, nbyte)   \
+	safe_pread(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \
+	    (buf), (nbyte), (offset))
+
 int	safe_setegid(const char *file, const int lineno,
 	    void (*cleanup_fn)(void), gid_t egid);
 #define SAFE_SETEGID(cleanup_fn, egid)	\
@@ -161,6 +167,13 @@ ssize_t	safe_write(const char *file, const int lineno,
 	safe_write(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \
 	    (buf), (nbyte))
 
+ssize_t safe_pwrite(const char *file, const int lineno, void (cleanup_fn)(void),
+	    char len_strict, int fildes, const void *buf, size_t nbyte,
+	    off_t offset);
+#define SAFE_PWRITE(cleanup_fn, len_strict, fildes, buf, nbyte, offset) \
+	safe_pwrite(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \
+	    (buf), (nbyte), (offset))
+
 long safe_strtol(const char *file, const int lineno,
 	    void (cleanup_fn)(void), char *str, long min, long max);
 #define SAFE_STRTOL(cleanup_fn, str, min, max) \
diff --git a/lib/safe_macros.c b/lib/safe_macros.c
index 90885fd..fb28c17 100644
--- a/lib/safe_macros.c
+++ b/lib/safe_macros.c
@@ -252,6 +252,22 @@ ssize_t safe_read(const char *file, const int lineno, void (*cleanup_fn) (void),
 	return rval;
 }
 
+ssize_t safe_pread(const char *file, const int lineno, void (*cleanup_fn)(void),
+		   char len_strict, int fildes, void *buf, size_t nbyte,
+		   off_t offset)
+{
+	ssize_t rval;
+
+	rval = pread(fildes, buf, nbyte, offset);
+	if (rval == -1 || (len_strict && (size_t)rval != nbyte)) {
+		tst_brkm(TBROK | TERRNO, cleanup_fn,
+			 "%s:%d: read(%d,%p,%zu, %ld) failed, returned %zd",
+			 file, lineno, fildes, buf, nbyte, offset, rval);
+	}
+
+	return rval;
+}
+
 int safe_setegid(const char *file, const int lineno, void (*cleanup_fn) (void),
                  gid_t egid)
 {
@@ -407,6 +423,22 @@ ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void),
 	return rval;
 }
 
+ssize_t safe_pwrite(const char *file, const int lineno,
+		    void (cleanup_fn) (void), char len_strict, int fildes,
+		    const void *buf, size_t nbyte, off_t offset)
+{
+	ssize_t rval;
+
+	rval = pwrite(fildes, buf, nbyte, offset);
+	if ((len_strict == 0 && rval == -1) || (size_t)rval != nbyte) {
+		tst_brkm(TBROK | TERRNO, cleanup_fn,
+			 "%s:%d: pwrite(%d,%p,%zu, %ld) failed",
+			 file, lineno, fildes, buf, rval, offset);
+	}
+
+	return rval;
+}
+
 long safe_strtol(const char *file, const int lineno,
 		 void (cleanup_fn) (void), char *str, long min, long max)
 {
-- 
1.8.3.1


------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
  2015-02-04  8:59     ` [LTP] [PATCH v2 1/2] lib: add SAFE_PWRITE() and SAFE_PREAD() Xiaoguang Wang
@ 2015-02-04  8:59       ` Xiaoguang Wang
  2015-02-06  7:09         ` Li Wang
  0 siblings, 1 reply; 9+ messages in thread
From: Xiaoguang Wang @ 2015-02-04  8:59 UTC (permalink / raw)
  To: ltp-list

This data corruption fixed by:
    commit 90a8020278c1598fafd071736a0846b38510309c
    Author: Jan Kara <jack@suse.cz>
    Date:   Wed Oct 1 21:49:18 2014 -0400
        vfs: fix data corruption when blocksize < pagesize for mmaped data

and this test is written to run in ext4 filesystem(with mount option 'nodelalloc'),
so there is another fixing patch needed:
    commit d6320cbfc92910a3e5f10c42d98c231c98db4f60
    Author: Jan Kara <jack@suse.cz>
    Date:   Wed Oct 1 21:49:46 2014 -0400
        ext4: fix mmap data corruption when blocksize < pagesize

Signed-off-by: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
---
 runtest/ltplite                         |   1 +
 runtest/stress.part3                    |   1 +
 runtest/syscalls                        |   1 +
 testcases/kernel/syscalls/.gitignore    |   1 +
 testcases/kernel/syscalls/mmap/mmap16.c | 247 ++++++++++++++++++++++++++++++++
 5 files changed, 251 insertions(+)
 create mode 100644 testcases/kernel/syscalls/mmap/mmap16.c

diff --git a/runtest/ltplite b/runtest/ltplite
index 1457908..5d6c815 100644
--- a/runtest/ltplite
+++ b/runtest/ltplite
@@ -449,6 +449,7 @@ mmap06 mmap06
 mmap07 mmap07
 mmap08 mmap08
 mmap09 mmap09
+mmap16 mmap16
 
 modify_ldt01 modify_ldt01
 modify_ldt02 modify_ldt02
diff --git a/runtest/stress.part3 b/runtest/stress.part3
index 368c640..48fcc5f 100644
--- a/runtest/stress.part3
+++ b/runtest/stress.part3
@@ -382,6 +382,7 @@ mmap06 mmap06
 mmap07 mmap07
 mmap08 mmap08
 mmap09 mmap09
+mmap16 mmap16 -i 5
 
 modify_ldt01 modify_ldt01
 modify_ldt02 modify_ldt02
diff --git a/runtest/syscalls b/runtest/syscalls
index 44969f3..4e780d7 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -587,6 +587,7 @@ mmap14 mmap14
 # test is broken, mask it for now.
 #mmap11 mmap11 -i 30000
 mmap15 mmap15
+mmap16 mmap16
 
 modify_ldt01 modify_ldt01
 modify_ldt02 modify_ldt02
diff --git a/testcases/kernel/syscalls/.gitignore b/testcases/kernel/syscalls/.gitignore
index 92c0bf5..b443fd8 100644
--- a/testcases/kernel/syscalls/.gitignore
+++ b/testcases/kernel/syscalls/.gitignore
@@ -533,6 +533,7 @@
 /mmap/mmap13
 /mmap/mmap14
 /mmap/mmap15
+/mmap/mmap16
 /modify_ldt/modify_ldt01
 /modify_ldt/modify_ldt02
 /modify_ldt/modify_ldt03
diff --git a/testcases/kernel/syscalls/mmap/mmap16.c b/testcases/kernel/syscalls/mmap/mmap16.c
new file mode 100644
index 0000000..7ce1544
--- /dev/null
+++ b/testcases/kernel/syscalls/mmap/mmap16.c
@@ -0,0 +1,247 @@
+/*
+ *   Copyright (c) 2015 Fujitsu Ltd.
+ *   Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
+ *
+ *   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.
+ */
+
+/*
+ * This is a regression test for commit:
+ * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
+ * commit/?id=90a8020
+ * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
+ * commit/?id=d6320cb
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+
+#include "usctest.h"
+#include "test.h"
+#include "safe_macros.h"
+
+#define MNTPOINT	"mntpoint"
+#define FS_BLOCKSIZE	1024
+#define SUB_LOOPCOUNT	10
+
+static void setup(void);
+static void cleanup(void);
+static void do_child(void);
+static void do_test(void);
+
+static const char *device;
+static const char *fs_type = "ext4";
+static int mount_flag;
+
+static int page_size;
+static struct tst_checkpoint checkpoint1, checkpoint2;
+static int bug_reproduced;
+
+char *TCID = "mmap16";
+int TST_TOTAL = 1;
+
+int main(int ac, char **av)
+{
+	int i, lc;
+	const char *msg;
+
+	msg = parse_opts(ac, av, NULL, NULL);
+	if (msg != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	setup();
+
+	/*
+	 * If child process was killed by SIGBUS, indeed that can not guarantee
+	 * this bug must have been fixed, If we're luckily enough, virtual
+	 * memory subsystem happen to decide that it is time to write dirty
+	 * pages, it will make mapped pages write-protect, so ->page_mkwrite()
+	 * still will be called, child process will be killed by SIGBUS, but
+	 * it's not because of above fixing patches. So here we run this test
+	 * 10 times, if once, child process exits normally, we can sure that
+	 * this bug is not fixed.
+	 */
+	for (lc = 0; TEST_LOOPING(lc); lc++) {
+		tst_count = 0;
+
+		for (i = 0; i < SUB_LOOPCOUNT; i++)
+			do_test();
+	}
+
+	if (bug_reproduced)
+		tst_resm(TFAIL, "Bug is reproduced!");
+	else
+		tst_resm(TPASS, "Bug is not reproduced!");
+
+	cleanup();
+	tst_exit();
+}
+
+static void do_test(void)
+{
+	int fd, ret, status;
+	pid_t child;
+	char buf[FS_BLOCKSIZE];
+
+	SAFE_TOUCH(cleanup, "testfilep", 0644, NULL);
+	SAFE_TOUCH(cleanup, "testfilec", 0644, NULL);
+
+	child = tst_fork();
+	switch (child) {
+	case -1:
+		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
+	case 0:
+		do_child();
+	default:
+		fd = SAFE_OPEN(cleanup, "testfilep", O_RDWR);
+		memset(buf, 'a', FS_BLOCKSIZE);
+
+		TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1);
+		while (1) {
+			ret = write(fd, buf, FS_BLOCKSIZE);
+			if (ret < 0) {
+				if (errno == ENOSPC) {
+					break;
+				} else {
+					tst_brkm(TBROK | TERRNO, cleanup,
+						 "write failed unexpectedly");
+				}
+			}
+		}
+		SAFE_CLOSE(cleanup, fd);
+		TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2);
+	}
+
+	wait(&status);
+	if (WIFEXITED(status) && WEXITSTATUS(status) == 1) {
+		bug_reproduced = 1;
+	} else {
+		/*
+		 * If child process was killed by SIGBUS, bug is not reproduced.
+		 */
+		if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+				 "child process terminate unexpectedly");
+		}
+	}
+
+	SAFE_UNLINK(cleanup, "testfilep");
+	SAFE_UNLINK(cleanup, "testfilec");
+}
+
+static void setup(void)
+{
+	const char *fs_opts[3] = {"-b", "1024", NULL};
+
+	tst_sig(FORK, DEF_HANDLER, NULL);
+	tst_require_root(NULL);
+
+	TEST_PAUSE;
+	tst_tmpdir();
+
+	page_size = getpagesize();
+	if (page_size == -1)
+		tst_brkm(TBROK | TERRNO, cleanup, "Unable to get page size");
+
+	device = tst_acquire_device(cleanup);
+	if (!device)
+		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
+	tst_mkfs(cleanup, device, fs_type, fs_opts);
+
+	SAFE_MKDIR(cleanup, MNTPOINT, 0755);
+	/*
+	 * Disable ext4 delalloc feature, so block will be allocated
+	 * as soon as possible
+	 */
+	SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, 0, "nodelalloc");
+	mount_flag = 1;
+
+	SAFE_CHDIR(cleanup, MNTPOINT);
+	TST_CHECKPOINT_CREATE(&checkpoint1);
+	TST_CHECKPOINT_CREATE(&checkpoint2);
+}
+
+static void do_child(void)
+{
+	int fd, offset;
+	char buf[FS_BLOCKSIZE];
+	char *addr = NULL;
+
+	/*
+	 * We have changed SIGBUS' handler in parent process by calling
+	 * tst_sig(FORK, DEF_HANDLER, NULL), so here just restore it.
+	 */
+	if (signal(SIGBUS, SIG_DFL) == SIG_ERR)
+		tst_brkm(TBROK | TERRNO, NULL, "signal(SIGBUS) failed");
+
+	memset(buf, 'a', FS_BLOCKSIZE);
+	fd = SAFE_OPEN(NULL, "testfilec", O_RDWR);
+	SAFE_PWRITE(NULL, 1, fd, buf, FS_BLOCKSIZE, 0);
+
+	/*
+	 * In case mremap() may fail because that memory area can not be
+	 * expanded at current virtual address(MREMAP_MAYMOVE is not set),
+	 * we first do a mmap(page_size * 2) operation to reserve some
+	 * free address space.
+	 */
+	addr = SAFE_MMAP(NULL, NULL, page_size * 2, PROT_WRITE | PROT_READ,
+			 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, -1, 0);
+	SAFE_MUNMAP(NULL, addr, page_size * 2);
+
+	addr = SAFE_MMAP(NULL, addr, FS_BLOCKSIZE, PROT_WRITE | PROT_READ,
+			 MAP_SHARED, fd, 0);
+
+	addr[0] = 'a';
+
+	SAFE_FTRUNCATE(NULL, fd, page_size * 2);
+	addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0);
+	if (addr == MAP_FAILED)
+		tst_brkm(TBROK | TERRNO, NULL, "mremap failed unexpectedly");
+
+	/*
+	 * Let parent process consume FS free blocks as many as possible, then
+	 * there'll be no free blocks allocated for this new file mmaping for
+	 * offset starting at 1024, 2048, or 3072. If this above kernel bug
+	 * has been fixed, usually child process will killed by SIGBUS signal,
+	 * if not, the data 'A', 'B', 'C' will be silently discarded later when
+	 * kernel writepage is called, that means data corruption.
+	 */
+	TST_CHECKPOINT_SIGNAL_PARENT(&checkpoint1);
+	TST_CHECKPOINT_CHILD_WAIT(&checkpoint2);
+
+	for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE)
+		addr[offset] = 'a';
+
+	SAFE_MUNMAP(NULL, addr, 2 * page_size);
+	SAFE_CLOSE(NULL, fd);
+	exit(TFAIL);
+}
+
+static void cleanup(void)
+{
+	TEST_CLEANUP;
+
+	if (chdir(".."))
+		tst_resm(TWARN | TERRNO, "chdir('..') failed");
+	if (mount_flag && tst_umount(MNTPOINT) < 0)
+		tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
+	if (device)
+		tst_release_device(NULL, device);
+	tst_rmdir();
+}
-- 
1.8.3.1


------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
  2015-02-04  8:59       ` [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data Xiaoguang Wang
@ 2015-02-06  7:09         ` Li Wang
  2015-02-06  7:13           ` Xiaoguang Wang
  0 siblings, 1 reply; 9+ messages in thread
From: Li Wang @ 2015-02-06  7:09 UTC (permalink / raw)
  To: Xiaoguang Wang; +Cc: ltp-list

Hi,

I found there are two new LTP changes have been applied, which would be
probably impact to your case:
commit aabb8340f63ed31afe995fd97795e542dc68b93c
    Include usctest.h in test.h
commit 605fa3362fd7cef0baa2131be32cf44661783d3e
    Get rid of TEST_CLEANUP

Seems we should remove two lines of the testcase as below otherwise it 
can't be compile.

BTW, I tested it on patched kernel it can works well and Bug reproduced
with unpatched kernel.

Thanks,
Li Wang

On Wed, 2015-02-04 at 16:59 +0800, Xiaoguang Wang wrote:
> This data corruption fixed by:
...
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <sys/mount.h>
> +#include <sys/mman.h>
> +
> +#include "usctest.h"    <=========== remove 
> +#include "test.h"
> +#include "safe_macros.h"
> +
> +#define MNTPOINT	"mntpoint"
> +#define FS_BLOCKSIZE	1024
...
> +
> +static void cleanup(void)
> +{
> +	TEST_CLEANUP;   <============ remove
> +
> +	if (chdir(".."))
> +		tst_resm(TWARN | TERRNO, "chdir('..') failed");
> +	if (mount_flag && tst_umount(MNTPOINT) < 0)
> +		tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
> +	if (device)
> +		tst_release_device(NULL, device);
> +	tst_rmdir();
> +}


------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
  2015-02-06  7:09         ` Li Wang
@ 2015-02-06  7:13           ` Xiaoguang Wang
  2015-02-10 10:29             ` Cyril Hrubis
  0 siblings, 1 reply; 9+ messages in thread
From: Xiaoguang Wang @ 2015-02-06  7:13 UTC (permalink / raw)
  To: Li Wang; +Cc: ltp-list

Hi,

On 02/06/2015 03:09 PM, Li Wang wrote:
> Hi,
> 
> I found there are two new LTP changes have been applied, which would be
> probably impact to your case:
> commit aabb8340f63ed31afe995fd97795e542dc68b93c
>     Include usctest.h in test.h
> commit 605fa3362fd7cef0baa2131be32cf44661783d3e
>     Get rid of TEST_CLEANUP
> 
> Seems we should remove two lines of the testcase as below otherwise it 
> can't be compile.

OK, thanks!
I'll send V3 next Monday, in case somebody has other comments ;)
> 
> BTW, I tested it on patched kernel it can works well and Bug reproduced
> with unpatched kernel.
Thanks!

Regards,
Xiaoguang Wang
> 
> Thanks,
> Li Wang
> 
> On Wed, 2015-02-04 at 16:59 +0800, Xiaoguang Wang wrote:
>> This data corruption fixed by:
> ...
>> +
>> +#include <stdio.h>
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <sys/types.h>
>> +#include <sys/wait.h>
>> +#include <unistd.h>
>> +#include <sys/mount.h>
>> +#include <sys/mman.h>
>> +
>> +#include "usctest.h"    <=========== remove 
>> +#include "test.h"
>> +#include "safe_macros.h"
>> +
>> +#define MNTPOINT	"mntpoint"
>> +#define FS_BLOCKSIZE	1024
> ...
>> +
>> +static void cleanup(void)
>> +{
>> +	TEST_CLEANUP;   <============ remove
>> +
>> +	if (chdir(".."))
>> +		tst_resm(TWARN | TERRNO, "chdir('..') failed");
>> +	if (mount_flag && tst_umount(MNTPOINT) < 0)
>> +		tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
>> +	if (device)
>> +		tst_release_device(NULL, device);
>> +	tst_rmdir();
>> +}
> 
> .
> 


------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
  2015-02-06  7:13           ` Xiaoguang Wang
@ 2015-02-10 10:29             ` Cyril Hrubis
  0 siblings, 0 replies; 9+ messages in thread
From: Cyril Hrubis @ 2015-02-10 10:29 UTC (permalink / raw)
  To: Xiaoguang Wang; +Cc: ltp-list

Hi!
> > I found there are two new LTP changes have been applied, which would be
> > probably impact to your case:
> > commit aabb8340f63ed31afe995fd97795e542dc68b93c
> >     Include usctest.h in test.h
> > commit 605fa3362fd7cef0baa2131be32cf44661783d3e
> >     Get rid of TEST_CLEANUP
> > 
> > Seems we should remove two lines of the testcase as below otherwise it 
> > can't be compile.
> 
> OK, thanks!
> I'll send V3 next Monday, in case somebody has other comments ;)

I've fixed that along with two smaller fixes and pushed the patches.

Thanks.

* The getpagesize() cannot fail so I've deleted the check for negative
  return value

* I've changed the cleanup to do the chdir("..") only if the chdir to
  MNTPOINT was successful. Otherwise it may have fail if the cleanup
  was called from the setup before the chdir() was done.

-- 
Cyril Hrubis
chrubis@suse.cz

------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data
       [not found]   ` <54D09440.7070701@cn.fujitsu.com>
@ 2015-02-03  9:45     ` Cyril Hrubis
  0 siblings, 0 replies; 9+ messages in thread
From: Cyril Hrubis @ 2015-02-03  9:45 UTC (permalink / raw)
  To: Xiaoguang Wang; +Cc: ltp-list

Hi!
> As you have pointed that we can use '-i num' in runtest file to make this test run
> multiple times, but if a user just chdir to testcases/kernel/syscalls/mmap/ and executes
> './mmap16' directly, and if also virtual memory subsystem happens to write dirty pages,
> test result will be not accurate. So here I still make this test run 10 times at lease ;)

You can then do two loops. One for the test itself and for the test
looping.

-- 
Cyril Hrubis
chrubis@suse.cz

------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-02-10 10:29 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1422876702-3152-1-git-send-email-wangxg.fnst@cn.fujitsu.com>
     [not found] ` <1422876702-3152-2-git-send-email-wangxg.fnst@cn.fujitsu.com>
2015-02-02 16:07   ` [LTP] [PATCH 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data Jan Stancek
2015-02-03  2:04     ` Xiaoguang Wang
2015-02-03  9:57   ` Cyril Hrubis
2015-02-04  8:59     ` [LTP] [PATCH v2 1/2] lib: add SAFE_PWRITE() and SAFE_PREAD() Xiaoguang Wang
2015-02-04  8:59       ` [LTP] [PATCH v2 2/2] syscalls/mmap16: regression test for data corruption when blocksize < pagesize for mmaped data Xiaoguang Wang
2015-02-06  7:09         ` Li Wang
2015-02-06  7:13           ` Xiaoguang Wang
2015-02-10 10:29             ` Cyril Hrubis
     [not found] <1422954897-11966-1-git-send-email-wangxg.fnst@cn.fujitsu.com>
     [not found] ` <1422954897-11966-2-git-send-email-wangxg.fnst@cn.fujitsu.com>
     [not found]   ` <54D09440.7070701@cn.fujitsu.com>
2015-02-03  9:45     ` [LTP] [PATCH " Cyril Hrubis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.