All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v3] dio_truncate.c test refactory with LTP API
@ 2021-11-17 16:47 Andrea Cervesato
  2021-11-18 10:51 ` Cyril Hrubis
  0 siblings, 1 reply; 2+ messages in thread
From: Andrea Cervesato @ 2021-11-17 16:47 UTC (permalink / raw)
  To: ltp

From: Andrea Cervesato <andrea.cervesato@suse.com>

---
 testcases/kernel/io/ltp-aiodio/dio_truncate.c | 195 ++++++------------
 1 file changed, 65 insertions(+), 130 deletions(-)

diff --git a/testcases/kernel/io/ltp-aiodio/dio_truncate.c b/testcases/kernel/io/ltp-aiodio/dio_truncate.c
index 27cf01525..d0d120614 100644
--- a/testcases/kernel/io/ltp-aiodio/dio_truncate.c
+++ b/testcases/kernel/io/ltp-aiodio/dio_truncate.c
@@ -1,159 +1,91 @@
-
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2004 Daniel McNeil <daniel@osdl.org>
- *               2004 Open Source Development Lab
- *   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
- *
- * Module: .c
+ *			    2004 Open Source Development Lab
+ *	Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
  */
 
-/*
- * Change History:
- *
- * 2/2004  Marty Ridgeway (mridge@us.ibm.com) Changes to adapt to LTP
- *
- */
 #define _GNU_SOURCE
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
 #include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <memory.h>
-#include <string.h>
-#include <limits.h>
-
-#include "test.h"
+#include "tst_test.h"
 
-#define NUM_CHILDREN 8
+#define NUM_CHILDREN 10
+#define FILE_SIZE (64 * 1024)
 
-char *check_zero(unsigned char *buf, int size)
-{
-	unsigned char *p;
-
-	p = buf;
-
-	while (size > 0) {
-		if (*buf != 0) {
-			fprintf(stderr,
-				"non zero buffer at buf[%d] => 0x%02x,%02x,%02x,%02x\n",
-				buf - p, (unsigned int)buf[0],
-				size > 1 ? (unsigned int)buf[1] : 0,
-				size > 2 ? (unsigned int)buf[2] : 0,
-				size > 3 ? (unsigned int)buf[3] : 0);
-			fprintf(stderr, "buf %p, p %p\n", buf, p);
-			return buf;
-		}
-		buf++;
-		size--;
-	}
-	return 0;		/* all zeros */
-}
-
-int dio_read(char *filename)
+static void dio_read(const char *filename, size_t bs, size_t bcount)
 {
 	int fd;
-	int r;
-	void *bufptr = NULL;
-
-	TEST(posix_memalign(&bufptr, 4096, 64 * 1024));
-	if (TEST_RETURN) {
-		tst_resm(TBROK | TRERRNO, "cannot malloc aligned memory");
-		return -1;
-	}
-
-	while ((fd = open(filename, O_DIRECT | O_RDONLY)) < 0) {
-	}
-	fprintf(stderr, "dio_truncate: child reading file\n");
-	while (1) {
-		off_t offset;
-		char *bufoff;
-
-		/* read the file, checking for zeros */
-		offset = lseek(fd, SEEK_SET, 0);
-		do {
-			r = read(fd, bufptr, 64 * 1024);
-			if (r > 0) {
-				if ((bufoff = check_zero(bufptr, r))) {
-					fprintf(stderr,
-						"non-zero read at offset %p\n",
-						offset + bufoff);
-					exit(1);
+	size_t i;
+	char *bufptr;
+	size_t iter = 0;
+
+	bufptr = SAFE_MEMALIGN(getpagesize(), bs);
+
+	while ((fd = open(filename, O_RDONLY | O_DIRECT, 0666)) < 0)
+		;
+	tst_res(TINFO, "child reading file");
+	while (iter < bcount) {
+		SAFE_LSEEK(fd, SEEK_SET, 0);
+
+		if (read(fd, bufptr, bs) > 0) {
+			for (i = 0; i < bs; i++) {
+				if (*bufptr != 0) {
+					tst_res(TFAIL, "non zero buffer at %lu", i);
+					SAFE_CLOSE(fd);
+					return;
 				}
-				offset += r;
+				bufptr++;
 			}
-		} while (r > 0);
+		}
+		iter++;
+		usleep(150);
 	}
-	return 0;
+
+	SAFE_CLOSE(fd);
+
+	tst_res(TPASS, "zero buffer only after truncate");
 }
 
-void dio_append(char *filename, int fill)
+static void dio_append(const char *path, char pattern, size_t bs, size_t bcount)
 {
 	int fd;
-	void *bufptr = NULL;
-	int i;
-	int w;
+	size_t i;
+	char *bufptr;
 
-	fd = open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666);
+	bufptr = SAFE_MEMALIGN(getpagesize(), bs);
+	memset(bufptr, pattern, bs);
 
-	if (fd < 0) {
-		perror("cannot create file");
-		return;
-	}
-
-	TEST(posix_memalign(&bufptr, 4096, 64 * 1024));
-	if (TEST_RETURN) {
-		tst_resm(TBROK | TRERRNO, "cannot malloc aligned memory");
-		close(fd);
-		return;
-	}
+	fd = SAFE_OPEN(path, O_CREAT | O_WRONLY | O_DIRECT, 0666);
 
-	memset(bufptr, fill, 64 * 1024);
+	for (i = 0; i < bcount; i++)
+		SAFE_WRITE(1, fd, bufptr, bs);
 
-	for (i = 0; i < 1000; i++) {
-		if ((w = write(fd, bufptr, 64 * 1024)) != 64 * 1024) {
-			fprintf(stderr, "write %d returned %d\n", i, w);
-		}
-	}
-	close(fd);
+	SAFE_CLOSE(fd);
 }
 
-int main(void)
+static void run(void)
 {
-	char filename[PATH_MAX];
+	char *filename = "file";
+	int filesize = FILE_SIZE;
+	int num_children = NUM_CHILDREN;
 	int pid[NUM_CHILDREN];
-	int num_children = 1;
 	int i;
 
-	snprintf(filename, sizeof(filename), "%s/aiodio/file",
-		 getenv("TMP") ? getenv("TMP") : "/tmp");
-
 	for (i = 0; i < num_children; i++) {
-		if ((pid[i] = fork()) == 0) {
+		pid[i] = fork();
+		if (pid[i] == 0) {
 			/* child */
-			return dio_read(filename);
+			dio_read(filename, filesize, 1000);
+			return;
 		} else if (pid[i] < 0) {
 			/* error */
-			perror("fork error");
+			tst_brk(TBROK, "fork error");
 			break;
-		} else {
-			/* Parent */
-			continue;
 		}
 	}
 
@@ -161,17 +93,20 @@ int main(void)
 	 * Parent creates a zero file using DIO.
 	 * Truncates it to zero
 	 * Create another file with '0xaa'
+	 * Truncates it to zero
 	 */
 	for (i = 0; i < 100; i++) {
-		dio_append(filename, 0);
-		truncate(filename, 0);
-		dio_append("junkfile", 0xaa);
-		truncate("junkfile", 0);
+		dio_append(filename, 0, filesize, 200);
+		SAFE_TRUNCATE(filename, 0);
+		dio_append("junkfile", 0xaa, filesize, 200);
+		SAFE_TRUNCATE("junkfile", 0);
 	}
 
-	for (i = 0; i < num_children; i++) {
-		kill(pid[i], SIGTERM);
-	}
-
-	return 0;
+	for (i = 0; i < num_children; i++)
+		SAFE_KILL(pid[i], SIGTERM);
 }
+
+static struct tst_test test = {
+	.needs_tmpdir = 1,
+	.test_all = run,
+};
-- 
2.33.1


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] [PATCH v3] dio_truncate.c test refactory with LTP API
  2021-11-17 16:47 [LTP] [PATCH v3] dio_truncate.c test refactory with LTP API Andrea Cervesato
@ 2021-11-18 10:51 ` Cyril Hrubis
  0 siblings, 0 replies; 2+ messages in thread
From: Cyril Hrubis @ 2021-11-18 10:51 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi!
This version is much better, there are still a few things to fix though.

Also something I haven't caught in previous reviews, the pach is missing
signed-off-by: line. See:

https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin

In short you should configure git with user name and email and then
commit with -s.

>  #define _GNU_SOURCE
>  
>  #include <stdlib.h>
> +#include <stdio.h>
> +#include <sys/stat.h>
>  #include <sys/types.h>
> -#include <signal.h>
> -#include <errno.h>
>  #include <fcntl.h>
> -#include <stdio.h>
> -#include <unistd.h>
> -#include <memory.h>
> -#include <string.h>
> -#include <limits.h>
> -
> -#include "test.h"
> +#include "tst_test.h"
>  
> -#define NUM_CHILDREN 8
> +#define NUM_CHILDREN 10
> +#define FILE_SIZE (64 * 1024)
>  
> -char *check_zero(unsigned char *buf, int size)
> -{
> -	unsigned char *p;
> -
> -	p = buf;
> -
> -	while (size > 0) {
> -		if (*buf != 0) {
> -			fprintf(stderr,
> -				"non zero buffer at buf[%d] => 0x%02x,%02x,%02x,%02x\n",
> -				buf - p, (unsigned int)buf[0],
> -				size > 1 ? (unsigned int)buf[1] : 0,
> -				size > 2 ? (unsigned int)buf[2] : 0,
> -				size > 3 ? (unsigned int)buf[3] : 0);
> -			fprintf(stderr, "buf %p, p %p\n", buf, p);
> -			return buf;
> -		}
> -		buf++;
> -		size--;
> -	}
> -	return 0;		/* all zeros */
> -}
> -
> -int dio_read(char *filename)
> +static void dio_read(const char *filename, size_t bs, size_t bcount)
>  {
>  	int fd;
> -	int r;
> -	void *bufptr = NULL;
> -
> -	TEST(posix_memalign(&bufptr, 4096, 64 * 1024));
> -	if (TEST_RETURN) {
> -		tst_resm(TBROK | TRERRNO, "cannot malloc aligned memory");
> -		return -1;
> -	}
> -
> -	while ((fd = open(filename, O_DIRECT | O_RDONLY)) < 0) {
> -	}
> -	fprintf(stderr, "dio_truncate: child reading file\n");
> -	while (1) {
> -		off_t offset;
> -		char *bufoff;
> -
> -		/* read the file, checking for zeros */
> -		offset = lseek(fd, SEEK_SET, 0);
> -		do {
> -			r = read(fd, bufptr, 64 * 1024);
> -			if (r > 0) {
> -				if ((bufoff = check_zero(bufptr, r))) {
> -					fprintf(stderr,
> -						"non-zero read at offset %p\n",
> -						offset + bufoff);
> -					exit(1);
> +	size_t i;
> +	char *bufptr;
> +	size_t iter = 0;
> +
> +	bufptr = SAFE_MEMALIGN(getpagesize(), bs);
> +
> +	while ((fd = open(filename, O_RDONLY | O_DIRECT, 0666)) < 0)
> +		;

We usually put short usleep() here to give the other threads chance to
run before we retry. Something as usleep(100); will do.

> +	tst_res(TINFO, "child reading file");
> +	while (iter < bcount) {
> +		SAFE_LSEEK(fd, SEEK_SET, 0);
> +
> +		if (read(fd, bufptr, bs) > 0) {
> +			for (i = 0; i < bs; i++) {
> +				if (*bufptr != 0) {
> +					tst_res(TFAIL, "non zero buffer at %lu", i);
> +					SAFE_CLOSE(fd);
> +					return;
>  				}
> -				offset += r;
> +				bufptr++;
>  			}
> -		} while (r > 0);
> +		}

You cannot really blindly trust read that it has returned as much as you
have asked for, especially when the file is being written to/truncated
by the other thread, it may return much less.

And the child processes should really continue to read until they are
told to stop. Since as it is they stop before the main thread finishes
writing to the file, which is kind of useless. I think that the optimal
way how to structure the test is to:

- the child exits the loop at the first non-zero byte

- the parent process that writes to the files checks if there is a child
  that did exit with SAFE_WAIPID(-1, &status, WNOHANG); and if there is
  one exits the whole test

- when the parent process has finished it signals the children to exit

  There are various ways how to do that:

    - the child sets up a signal handler that would set global variable
      should_run to 0
    - the child then has a while (should_run) { } in the main loop
    - parent signals all the children and they would exit


    - parent kills the children with SIGKILL and then waits them in a
      loop until there are none left


    - parent sets up a piece of shared memory with int *should_run = mmap(...);
    - the children do while (*should_run) { } in the main loop
    - parent does *should_run = 0 to stop them


Also I think that it was better structured when the non-zero check was
in a separate function and printed the actuall bytes and offset.

> +		iter++;
> +		usleep(150);
>  	}
> -	return 0;
> +
> +	SAFE_CLOSE(fd);
> +
> +	tst_res(TPASS, "zero buffer only after truncate");
>  }
>  
> -void dio_append(char *filename, int fill)
> +static void dio_append(const char *path, char pattern, size_t bs, size_t bcount)
>  {
>  	int fd;
> -	void *bufptr = NULL;
> -	int i;
> -	int w;
> +	size_t i;
> +	char *bufptr;
>  
> -	fd = open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666);
> +	bufptr = SAFE_MEMALIGN(getpagesize(), bs);
> +	memset(bufptr, pattern, bs);
>  
> -	if (fd < 0) {
> -		perror("cannot create file");
> -		return;
> -	}
> -
> -	TEST(posix_memalign(&bufptr, 4096, 64 * 1024));
> -	if (TEST_RETURN) {
> -		tst_resm(TBROK | TRERRNO, "cannot malloc aligned memory");
> -		close(fd);
> -		return;
> -	}
> +	fd = SAFE_OPEN(path, O_CREAT | O_WRONLY | O_DIRECT, 0666);
>  
> -	memset(bufptr, fill, 64 * 1024);
> +	for (i = 0; i < bcount; i++)
> +		SAFE_WRITE(1, fd, bufptr, bs);
>  
> -	for (i = 0; i < 1000; i++) {
> -		if ((w = write(fd, bufptr, 64 * 1024)) != 64 * 1024) {
> -			fprintf(stderr, "write %d returned %d\n", i, w);
> -		}
> -	}
> -	close(fd);
> +	SAFE_CLOSE(fd);
>  }
>  
> -int main(void)
> +static void run(void)
>  {
> -	char filename[PATH_MAX];
> +	char *filename = "file";
> +	int filesize = FILE_SIZE;
> +	int num_children = NUM_CHILDREN;
>  	int pid[NUM_CHILDREN];
> -	int num_children = 1;
>  	int i;
>  
> -	snprintf(filename, sizeof(filename), "%s/aiodio/file",
> -		 getenv("TMP") ? getenv("TMP") : "/tmp");
> -
>  	for (i = 0; i < num_children; i++) {
> -		if ((pid[i] = fork()) == 0) {
> +		pid[i] = fork();
> +		if (pid[i] == 0) {
>  			/* child */
> -			return dio_read(filename);
> +			dio_read(filename, filesize, 1000);
> +			return;
>  		} else if (pid[i] < 0) {
>  			/* error */
> -			perror("fork error");
> +			tst_brk(TBROK, "fork error");
>  			break;
> -		} else {
> -			/* Parent */
> -			continue;
>  		}
>  	}

Please use SAFE_FORK() instead.

> @@ -161,17 +93,20 @@ int main(void)
>  	 * Parent creates a zero file using DIO.
>  	 * Truncates it to zero
>  	 * Create another file with '0xaa'
> +	 * Truncates it to zero
>  	 */

This description should be moved to a top level special documentation
comment and formatted in asciidoc so that it's picked up by the
documentation parser.

The comment looks like:

/*\
 * [Description]
 *
 * This is an ascii doc formatted test description.
 *
 * - list item #1
 * - list item #2
 */

And when you have asciidoc installed the LTP builds a
docparse/metadata.html file which contains the documentation for all
tests that have it included.

I guess that we should write some documentation for the format as
well.

>  	for (i = 0; i < 100; i++) {
> -		dio_append(filename, 0);
> -		truncate(filename, 0);
> -		dio_append("junkfile", 0xaa);
> -		truncate("junkfile", 0);
> +		dio_append(filename, 0, filesize, 200);
> +		SAFE_TRUNCATE(filename, 0);
> +		dio_append("junkfile", 0xaa, filesize, 200);
> +		SAFE_TRUNCATE("junkfile", 0);
>  	}
>  
> -	for (i = 0; i < num_children; i++) {
> -		kill(pid[i], SIGTERM);
> -	}
> -
> -	return 0;
> +	for (i = 0; i < num_children; i++)
> +		SAFE_KILL(pid[i], SIGTERM);
>  }
> +
> +static struct tst_test test = {
> +	.needs_tmpdir = 1,
> +	.test_all = run,
> +};
> -- 
> 2.33.1
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

end of thread, other threads:[~2021-11-18 10:50 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-17 16:47 [LTP] [PATCH v3] dio_truncate.c test refactory with LTP API Andrea Cervesato
2021-11-18 10:51 ` 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.