diff mbox series

syscalls/readv02: Convert to new API and merge readv03 into readv02.

Message ID 1627624085-16182-1-git-send-email-daisl.fnst@fujitsu.com
State Changes Requested
Headers show
Series syscalls/readv02: Convert to new API and merge readv03 into readv02. | expand

Commit Message

Dai Shili July 30, 2021, 5:48 a.m. UTC
1) merge readv03 into readv02
2) use tst_get_bad_addr() API
3) use TST_EXP_FAIL2 macro

Signed-off-by: Dai Shili <daisl.fnst@fujitsu.com>
---
 runtest/syscalls                           |   1 -
 testcases/kernel/syscalls/readv/.gitignore |   1 -
 testcases/kernel/syscalls/readv/readv02.c  | 331 ++++++++++-------------------
 testcases/kernel/syscalls/readv/readv03.c  |  53 -----
 4 files changed, 108 insertions(+), 278 deletions(-)
 delete mode 100644 testcases/kernel/syscalls/readv/readv03.c

Comments

Cyril Hrubis Aug. 3, 2021, 1:43 p.m. UTC | #1
Hi!
> -	/* Test case #1 */
> +static struct iovec rd_iovec[MAX_IOVEC] = {
>  	{buf2, -1},
>  	{(buf2 + CHUNK), CHUNK},
>  	{(buf2 + CHUNK * 2), CHUNK},
> -
> -	/* Test case #2 */
>  	{(buf2 + CHUNK * 3), G_1},
>  	{(buf2 + CHUNK * 4), G_1},
>  	{(buf2 + CHUNK * 5), G_1},
> -
> -	/* Test case #3 */
>  	{(caddr_t) - 1, CHUNK},
>  	{(buf2 + CHUNK * 6), CHUNK},
>  	{(buf2 + CHUNK * 8), CHUNK},
> -
> -	/* Test case #4 */
> -	{(buf2 + CHUNK * 9), CHUNK}
> +	{(buf2 + CHUNK * 9), CHUNK},
> +	{buf1, K_1}
>  };

It would be much easier to read the code if we split this iovec so that
each test has it's own structure. There is absolutely no reason to keep
them all together like that.

I.e. we will have it as:

static struct iovec invalid_iovec[] = {
	{buf, -1},
	{buf + CHUNK, CHUNK},
	{buf + 2*CHUNK, CHUNK},
};

static struct iovec large_iovec[] = {
	{buf2, G_1},
	{buf2 + CHUNK, G_1},
	{buf2 + CHUNK*2, G_1},
};

static struct iovec efault_iovec[] = {
	{NULL, CHUNK},
	{buf + CHUNK, CHUNK},
	{buf + 2*CHUNK, CHUNK},
};

static struct iovec valid_iovec[] = {
	{buf, CHUNK},
};

Also we can use the valid iovec for both EISDIR and EBADFD.

static void setup(void)
{
	...
	efault_iovec[0].iov_base = tst_get_bad_addr(NULL);
	...
}

Also I do not think that we need three buffers, the buf3 is completely
unused and there is no point in having special buffer for badfd test
either.

> -char f_name[K_1];
> -
> -int fd[4];
> -char *buf_list[NBUFS];
> -
> -char *TCID = "readv02";
> -int TST_TOTAL = 1;
> -
> -char *bad_addr = 0;
> +static struct tcase {
> +	int *fd;
> +	void *buf;
> +	int count;
> +	int exp_error;
> +} tcases[] = {
> +	{&fd[0], rd_iovec, 1, EINVAL},
> +	{&fd[1], rd_iovec + 6, 3, EFAULT},
> +	{&fd[2], rd_iovec + 10, -1, EINVAL},
> +	{&fd[3], rd_iovec + 10, 1, EISDIR},
> +	{&badfd, rd_iovec + 9, 3, EBADF},
> +};
>  
> -int init_buffs(char **);
> -int fill_mem(char *, int, int);
> -long l_seek(int, long, int);
> -char *getenv();
> -void setup();
> -void cleanup();
>  
> -int main(int ac, char **av)
> +void fill_mem(char *c_ptr, int c1, int c2)
>  {
> -	int lc;
> -
> -	tst_parse_opts(ac, av, NULL, NULL);
> -
> -	setup();
> +	int count;
>  
> -	/* The following loop checks looping state if -i option given */
> -	for (lc = 0; TEST_LOOPING(lc); lc++) {
> +	for (count = 1; count <= K_1 / CHUNK; count++) {
> +		if (count & 0x01) /* if odd */
> +			memset(c_ptr, c1, CHUNK);
> +		else /* if even */
> +			memset(c_ptr, c2, CHUNK);
> +	}
> +	return;
> +}
>  
> -		/* reset tst_count in case we are looping */
> -		tst_count = 0;
> +void init_buffs(char *pbufs[])
> +{
> +	int i;
>  
> -//test1:
> -		if (readv(fd[0], rd_iovec, 1) < 0) {
> -			if (errno != EINVAL) {
> -				tst_resm(TFAIL, "readv() set an illegal errno:"
> -					 " expected: EINVAL, got %d", errno);
> -			} else {
> -				tst_resm(TPASS, "got EINVAL");
> -			}
> -		} else {
> -			tst_resm(TFAIL, "Error: readv returned a positive "
> -				 "value");
> +	for (i = 0; pbufs[i] != NULL; i++) {
> +		switch (i) {
> +		case 0:
> +		case 1:
> +			fill_mem(pbufs[i], 0, 1);
> +			break;
> +		case 2:
> +			fill_mem(pbufs[i], 1, 0);
> +			break;
> +		default:
> +			tst_brk(TBROK, "Error in init_buffs function");
>  		}
> +	}
> +	return;
> +}
>  
> -//test2:
> -		l_seek(fd[0], CHUNK * 6, 0);
> -		if (readv(fd[0], (rd_iovec + 6), 3) < 0) {
> -			if (errno != EFAULT) {
> -				tst_resm(TFAIL, "expected errno = EFAULT, "
> -					 "got %d", errno);
> -			} else {
> -				tst_resm(TPASS, "got EFAULT");
> -			}
> -			if (memcmp((buf_list[0] + CHUNK * 6),
> -				   (buf_list[1] + CHUNK * 6), CHUNK * 3) != 0) {
> -				tst_resm(TFAIL, "Error: readv() partially "
> -					 "overlaid buf[2]");
> -			}
> -		} else {
> -			tst_resm(TFAIL, "Error: readv returned a positive "
> -				 "value");
> -		}
> +static void verify_readv(unsigned int n)
> +{
> +	struct tcase *tc = &tcases[n];
>  
> -//test3:
> -		if (readv(fd[1], (rd_iovec + 9), 1) < 0) {
> -			if (errno != EBADF) {
> -				tst_resm(TFAIL, "expected errno = EBADF, "
> -					 "got %d", errno);
> -			} else {
> -				tst_resm(TPASS, "got EBADF");
> -			}
> -		} else {
> -			tst_resm(TFAIL, "Error: readv returned a positive "
> -				 "value");
> -		}
> +	TST_EXP_FAIL2(readv(*tc->fd, tc->buf, tc->count), tc->exp_error,
> +		"readv(%d, %p, %d)", *tc->fd, tc->buf, tc->count);
>  
> -//test4:
> -		l_seek(fd[0], CHUNK * 10, 0);
> -		if (readv(fd[0], (rd_iovec + 10), -1) < 0) {
> -			if (errno != EINVAL) {
> -				tst_resm(TFAIL, "expected errno = EINVAL, "
> -					 "got %d", errno);
> -			} else {
> -				tst_resm(TPASS, "got EINVAL");
> -			}
> -		} else {
> -			tst_resm(TFAIL, "Error: readv returned a positive "
> -				 "value");
> +	if (tc->exp_error == EFAULT) {
> +		if (memcmp((buf_list[0] + CHUNK * 6),
> +			(buf_list[1] + CHUNK * 6), CHUNK * 3)) {
> +		    tst_res(TFAIL, "Error: readv() partially overlaid buf[2]");
>  		}
> -
>  	}
> -	close(fd[0]);
> -	close(fd[1]);
> -	cleanup();
> -	tst_exit();
> -
>  }
>  
> -/*
> - * setup() - performs all ONE TIME setup for this test.
> - */
>  void setup(void)
>  {
> -	int nbytes;
> -
> -	tst_sig(NOFORK, DEF_HANDLER, cleanup);
> -
> -	TEST_PAUSE;
> -
> -	/* make a temporary directory and cd to it */
> -	tst_tmpdir();
> +	int i;
>  
>  	buf_list[0] = buf1;
>  	buf_list[1] = buf2;
> @@ -201,84 +133,37 @@ void setup(void)
>  
>  	init_buffs(buf_list);
>  
> -	sprintf(f_name, "%s.%d", DATA_FILE, getpid());
> +	for (i = 0; i < 3; i++) {
> +		fd[i] = SAFE_OPEN(TEST_FILE[i], O_WRONLY | O_CREAT, 0666);
> +		SAFE_WRITE(1, fd[i], buf_list[2], K_1);
>  
> -	if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
> -		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
> -			 "errno = %d", f_name, errno);
> -	} else {
> -		if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) {
> -			tst_brkm(TBROK, cleanup, "write failed: nbytes "
> -				 "= %d " "errno = %d", nbytes, errno);
> -		}
> -	}
> +		SAFE_CLOSE(fd[i]);
>  
> -	SAFE_CLOSE(cleanup, fd[0]);
> -
> -	if ((fd[0] = open(f_name, O_RDONLY, 0666)) < 0) {
> -		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
> -			 "errno = %d", f_name, errno);
> +		fd[i] = SAFE_OPEN(TEST_FILE[i], O_RDONLY, 0666);
>  	}
> +	SAFE_LSEEK(fd[1], CHUNK * 6, 0);
> +	SAFE_LSEEK(fd[2], CHUNK * 10, 0);

Does these readv calls actually read anyting?

Because as far as I can tell they just fail without actually reading
anything, so there is no point in intializing the buffers and also there
is no point in having three different files opened for the test either.

> -	fd[1] = -1;		/* Invalid file descriptor */
> +	rd_iovec[6].iov_base = tst_get_bad_addr(NULL);
>  
> -	bad_addr = mmap(0, 1, PROT_NONE,
> -			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
> -	if (bad_addr == MAP_FAILED) {
> -		tst_brkm(TBROK, cleanup, "mmap failed");
> -	}
> -	rd_iovec[6].iov_base = bad_addr;
> +	SAFE_MKDIR(TEST_DIR, MODES);
> +	fd[3] = SAFE_OPEN(TEST_DIR, O_RDONLY);
>  }
>  
> -/*
> - * cleanup() - performs all ONE TIME cleanup for this test at
> - *	       completion or premature exit.
> - */
> -void cleanup(void)
> -{
> -	SAFE_UNLINK(NULL, f_name);
> -	tst_rmdir();
> -
> -}
> -
> -int init_buffs(char *pbufs[])
> +static void cleanup(void)
>  {
>  	int i;
>  
> -	for (i = 0; pbufs[i] != NULL; i++) {
> -		switch (i) {
> -		case 0:
> -		 /*FALLTHROUGH*/ case 1:
> -			fill_mem(pbufs[i], 0, 1);
> -			break;
> -
> -		case 2:
> -			fill_mem(pbufs[i], 1, 0);
> -			break;
> -
> -		default:
> -			tst_brkm(TBROK, cleanup, "Error in init_buffs()");
> -		}
> -	}
> -	return 0;
> -}
> -
> -int fill_mem(char *c_ptr, int c1, int c2)
> -{
> -	int count;
> -
> -	for (count = 1; count <= K_1 / CHUNK; count++) {
> -		if (count & 0x01) {	/* if odd */
> -			memset(c_ptr, c1, CHUNK);
> -		} else {	/* if even */
> -			memset(c_ptr, c2, CHUNK);
> -		}
> +	for (i = 0; i < 4; i++) {
> +		if (fd[i] > 0)
> +			SAFE_CLOSE(fd[i]);
>  	}
> -	return 0;
>  }
>  
> -long l_seek(int fdesc, long offset, int whence)
> -{
> -	SAFE_LSEEK(cleanup, fdesc, offset, whence);
> -	return 0;
> -}
> +static struct tst_test test = {
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.needs_tmpdir = 1,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.test = verify_readv,
> +};
Dai Shili Aug. 4, 2021, 9:37 a.m. UTC | #2
Hi Cyril,

Thank you very much for your comments. I will send a v2.

> -----邮件原件-----
> 发件人: Cyril Hrubis <chrubis@suse.cz>
> 发送时间: 2021年8月3日 21:44
> 收件人: Dai, Shili/戴 世丽 <daisl.fnst@fujitsu.com>
> 抄送: ltp@lists.linux.it
> 主题: Re: [LTP] [PATCH] syscalls/readv02: Convert to new API and merge
> readv03 into readv02.
> 
> Hi!
> > -	/* Test case #1 */
> > +static struct iovec rd_iovec[MAX_IOVEC] = {
> >  	{buf2, -1},
> >  	{(buf2 + CHUNK), CHUNK},
> >  	{(buf2 + CHUNK * 2), CHUNK},
> > -
> > -	/* Test case #2 */
> >  	{(buf2 + CHUNK * 3), G_1},
> >  	{(buf2 + CHUNK * 4), G_1},
> >  	{(buf2 + CHUNK * 5), G_1},
> > -
> > -	/* Test case #3 */
> >  	{(caddr_t) - 1, CHUNK},
> >  	{(buf2 + CHUNK * 6), CHUNK},
> >  	{(buf2 + CHUNK * 8), CHUNK},
> > -
> > -	/* Test case #4 */
> > -	{(buf2 + CHUNK * 9), CHUNK}
> > +	{(buf2 + CHUNK * 9), CHUNK},
> > +	{buf1, K_1}
> >  };
> 
> It would be much easier to read the code if we split this iovec so that each test
> has it's own structure. There is absolutely no reason to keep them all together
> like that.
> 
> I.e. we will have it as:
> 
> static struct iovec invalid_iovec[] = {
> 	{buf, -1},
> 	{buf + CHUNK, CHUNK},
> 	{buf + 2*CHUNK, CHUNK},
> };
> 
> static struct iovec large_iovec[] = {
> 	{buf2, G_1},
> 	{buf2 + CHUNK, G_1},
> 	{buf2 + CHUNK*2, G_1},
> };
> 
> static struct iovec efault_iovec[] = {
> 	{NULL, CHUNK},
> 	{buf + CHUNK, CHUNK},
> 	{buf + 2*CHUNK, CHUNK},
> };
> 
> static struct iovec valid_iovec[] = {
> 	{buf, CHUNK},
> };
> 
> Also we can use the valid iovec for both EISDIR and EBADFD.
> 
> static void setup(void)
> {
> 	...
> 	efault_iovec[0].iov_base = tst_get_bad_addr(NULL);
> 	...
> }
> 
> Also I do not think that we need three buffers, the buf3 is completely unused
> and there is no point in having special buffer for badfd test either.
> 
> > -char f_name[K_1];
> > -
> > -int fd[4];
> > -char *buf_list[NBUFS];
> > -
> > -char *TCID = "readv02";
> > -int TST_TOTAL = 1;
> > -
> > -char *bad_addr = 0;
> > +static struct tcase {
> > +	int *fd;
> > +	void *buf;
> > +	int count;
> > +	int exp_error;
> > +} tcases[] = {
> > +	{&fd[0], rd_iovec, 1, EINVAL},
> > +	{&fd[1], rd_iovec + 6, 3, EFAULT},
> > +	{&fd[2], rd_iovec + 10, -1, EINVAL},
> > +	{&fd[3], rd_iovec + 10, 1, EISDIR},
> > +	{&badfd, rd_iovec + 9, 3, EBADF},
> > +};
> >
> > -int init_buffs(char **);
> > -int fill_mem(char *, int, int);
> > -long l_seek(int, long, int);
> > -char *getenv();
> > -void setup();
> > -void cleanup();
> >
> > -int main(int ac, char **av)
> > +void fill_mem(char *c_ptr, int c1, int c2)
> >  {
> > -	int lc;
> > -
> > -	tst_parse_opts(ac, av, NULL, NULL);
> > -
> > -	setup();
> > +	int count;
> >
> > -	/* The following loop checks looping state if -i option given */
> > -	for (lc = 0; TEST_LOOPING(lc); lc++) {
> > +	for (count = 1; count <= K_1 / CHUNK; count++) {
> > +		if (count & 0x01) /* if odd */
> > +			memset(c_ptr, c1, CHUNK);
> > +		else /* if even */
> > +			memset(c_ptr, c2, CHUNK);
> > +	}
> > +	return;
> > +}
> >
> > -		/* reset tst_count in case we are looping */
> > -		tst_count = 0;
> > +void init_buffs(char *pbufs[])
> > +{
> > +	int i;
> >
> > -//test1:
> > -		if (readv(fd[0], rd_iovec, 1) < 0) {
> > -			if (errno != EINVAL) {
> > -				tst_resm(TFAIL, "readv() set an illegal errno:"
> > -					 " expected: EINVAL, got %d", errno);
> > -			} else {
> > -				tst_resm(TPASS, "got EINVAL");
> > -			}
> > -		} else {
> > -			tst_resm(TFAIL, "Error: readv returned a positive "
> > -				 "value");
> > +	for (i = 0; pbufs[i] != NULL; i++) {
> > +		switch (i) {
> > +		case 0:
> > +		case 1:
> > +			fill_mem(pbufs[i], 0, 1);
> > +			break;
> > +		case 2:
> > +			fill_mem(pbufs[i], 1, 0);
> > +			break;
> > +		default:
> > +			tst_brk(TBROK, "Error in init_buffs function");
> >  		}
> > +	}
> > +	return;
> > +}
> >
> > -//test2:
> > -		l_seek(fd[0], CHUNK * 6, 0);
> > -		if (readv(fd[0], (rd_iovec + 6), 3) < 0) {
> > -			if (errno != EFAULT) {
> > -				tst_resm(TFAIL, "expected errno = EFAULT, "
> > -					 "got %d", errno);
> > -			} else {
> > -				tst_resm(TPASS, "got EFAULT");
> > -			}
> > -			if (memcmp((buf_list[0] + CHUNK * 6),
> > -				   (buf_list[1] + CHUNK * 6), CHUNK * 3) != 0) {
> > -				tst_resm(TFAIL, "Error: readv() partially "
> > -					 "overlaid buf[2]");
> > -			}
> > -		} else {
> > -			tst_resm(TFAIL, "Error: readv returned a positive "
> > -				 "value");
> > -		}
> > +static void verify_readv(unsigned int n) {
> > +	struct tcase *tc = &tcases[n];
> >
> > -//test3:
> > -		if (readv(fd[1], (rd_iovec + 9), 1) < 0) {
> > -			if (errno != EBADF) {
> > -				tst_resm(TFAIL, "expected errno = EBADF, "
> > -					 "got %d", errno);
> > -			} else {
> > -				tst_resm(TPASS, "got EBADF");
> > -			}
> > -		} else {
> > -			tst_resm(TFAIL, "Error: readv returned a positive "
> > -				 "value");
> > -		}
> > +	TST_EXP_FAIL2(readv(*tc->fd, tc->buf, tc->count), tc->exp_error,
> > +		"readv(%d, %p, %d)", *tc->fd, tc->buf, tc->count);
> >
> > -//test4:
> > -		l_seek(fd[0], CHUNK * 10, 0);
> > -		if (readv(fd[0], (rd_iovec + 10), -1) < 0) {
> > -			if (errno != EINVAL) {
> > -				tst_resm(TFAIL, "expected errno = EINVAL, "
> > -					 "got %d", errno);
> > -			} else {
> > -				tst_resm(TPASS, "got EINVAL");
> > -			}
> > -		} else {
> > -			tst_resm(TFAIL, "Error: readv returned a positive "
> > -				 "value");
> > +	if (tc->exp_error == EFAULT) {
> > +		if (memcmp((buf_list[0] + CHUNK * 6),
> > +			(buf_list[1] + CHUNK * 6), CHUNK * 3)) {
> > +		    tst_res(TFAIL, "Error: readv() partially overlaid buf[2]");
> >  		}
> > -
> >  	}
> > -	close(fd[0]);
> > -	close(fd[1]);
> > -	cleanup();
> > -	tst_exit();
> > -
> >  }
> >
> > -/*
> > - * setup() - performs all ONE TIME setup for this test.
> > - */
> >  void setup(void)
> >  {
> > -	int nbytes;
> > -
> > -	tst_sig(NOFORK, DEF_HANDLER, cleanup);
> > -
> > -	TEST_PAUSE;
> > -
> > -	/* make a temporary directory and cd to it */
> > -	tst_tmpdir();
> > +	int i;
> >
> >  	buf_list[0] = buf1;
> >  	buf_list[1] = buf2;
> > @@ -201,84 +133,37 @@ void setup(void)
> >
> >  	init_buffs(buf_list);
> >
> > -	sprintf(f_name, "%s.%d", DATA_FILE, getpid());
> > +	for (i = 0; i < 3; i++) {
> > +		fd[i] = SAFE_OPEN(TEST_FILE[i], O_WRONLY | O_CREAT, 0666);
> > +		SAFE_WRITE(1, fd[i], buf_list[2], K_1);
> >
> > -	if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
> > -		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
> > -			 "errno = %d", f_name, errno);
> > -	} else {
> > -		if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) {
> > -			tst_brkm(TBROK, cleanup, "write failed: nbytes "
> > -				 "= %d " "errno = %d", nbytes, errno);
> > -		}
> > -	}
> > +		SAFE_CLOSE(fd[i]);
> >
> > -	SAFE_CLOSE(cleanup, fd[0]);
> > -
> > -	if ((fd[0] = open(f_name, O_RDONLY, 0666)) < 0) {
> > -		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
> > -			 "errno = %d", f_name, errno);
> > +		fd[i] = SAFE_OPEN(TEST_FILE[i], O_RDONLY, 0666);
> >  	}
> > +	SAFE_LSEEK(fd[1], CHUNK * 6, 0);
> > +	SAFE_LSEEK(fd[2], CHUNK * 10, 0);
> 
> Does these readv calls actually read anyting?
> 
> Because as far as I can tell they just fail without actually reading anything, so
> there is no point in intializing the buffers and also there is no point in having
> three different files opened for the test either.
> 
> > -	fd[1] = -1;		/* Invalid file descriptor */
> > +	rd_iovec[6].iov_base = tst_get_bad_addr(NULL);
> >
> > -	bad_addr = mmap(0, 1, PROT_NONE,
> > -			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
> > -	if (bad_addr == MAP_FAILED) {
> > -		tst_brkm(TBROK, cleanup, "mmap failed");
> > -	}
> > -	rd_iovec[6].iov_base = bad_addr;
> > +	SAFE_MKDIR(TEST_DIR, MODES);
> > +	fd[3] = SAFE_OPEN(TEST_DIR, O_RDONLY);
> >  }
> >
> > -/*
> > - * cleanup() - performs all ONE TIME cleanup for this test at
> > - *	       completion or premature exit.
> > - */
> > -void cleanup(void)
> > -{
> > -	SAFE_UNLINK(NULL, f_name);
> > -	tst_rmdir();
> > -
> > -}
> > -
> > -int init_buffs(char *pbufs[])
> > +static void cleanup(void)
> >  {
> >  	int i;
> >
> > -	for (i = 0; pbufs[i] != NULL; i++) {
> > -		switch (i) {
> > -		case 0:
> > -		 /*FALLTHROUGH*/ case 1:
> > -			fill_mem(pbufs[i], 0, 1);
> > -			break;
> > -
> > -		case 2:
> > -			fill_mem(pbufs[i], 1, 0);
> > -			break;
> > -
> > -		default:
> > -			tst_brkm(TBROK, cleanup, "Error in init_buffs()");
> > -		}
> > -	}
> > -	return 0;
> > -}
> > -
> > -int fill_mem(char *c_ptr, int c1, int c2) -{
> > -	int count;
> > -
> > -	for (count = 1; count <= K_1 / CHUNK; count++) {
> > -		if (count & 0x01) {	/* if odd */
> > -			memset(c_ptr, c1, CHUNK);
> > -		} else {	/* if even */
> > -			memset(c_ptr, c2, CHUNK);
> > -		}
> > +	for (i = 0; i < 4; i++) {
> > +		if (fd[i] > 0)
> > +			SAFE_CLOSE(fd[i]);
> >  	}
> > -	return 0;
> >  }
> >
> > -long l_seek(int fdesc, long offset, int whence) -{
> > -	SAFE_LSEEK(cleanup, fdesc, offset, whence);
> > -	return 0;
> > -}
> > +static struct tst_test test = {
> > +	.tcnt = ARRAY_SIZE(tcases),
> > +	.needs_tmpdir = 1,
> > +	.setup = setup,
> > +	.cleanup = cleanup,
> > +	.test = verify_readv,
> > +};
> 
> --
> Cyril Hrubis
> chrubis@suse.cz
diff mbox series

Patch

diff --git a/runtest/syscalls b/runtest/syscalls
index b379b2d..9c3b510 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1085,7 +1085,6 @@  readlinkat02 readlinkat02
 
 readv01 readv01
 readv02 readv02
-readv03 readv03
 
 realpath01 realpath01
 
diff --git a/testcases/kernel/syscalls/readv/.gitignore b/testcases/kernel/syscalls/readv/.gitignore
index c4aa61e..a532741 100644
--- a/testcases/kernel/syscalls/readv/.gitignore
+++ b/testcases/kernel/syscalls/readv/.gitignore
@@ -1,3 +1,2 @@ 
 /readv01
 /readv02
-/readv03
diff --git a/testcases/kernel/syscalls/readv/readv02.c b/testcases/kernel/syscalls/readv/readv02.c
index aa40e2c..aaadae0 100644
--- a/testcases/kernel/syscalls/readv/readv02.c
+++ b/testcases/kernel/syscalls/readv/readv02.c
@@ -1,198 +1,130 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
- *
- *   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
+ * Copyright (C) Bull S.A. 2001
+ * Copyright (c) International Business Machines  Corp., 2001
+ * 07/2001 Ported by Wayne Boyer
+ * 05/2002 Ported by Jacky Malcles
  */
 
-/*
- * NAME
- * 	readv02.c
- *
+/*\
  * DESCRIPTION
- *	Testcase to check the error conditions of the readv(2) system call.
+ *  test 1:
+ *  The sum of the iov_len values overflows an ssize_t value, expect an EINVAL.
  *
- * CALLS
- * 	readv()
+ *  test 2:
+ *  Buf is outside the accessible address space, expect an EFAULT.
  *
- * ALGORITHM
- *	Create a IO vector, and attempt to readv() various components of it.
+ *  test 3:
+ *  The vector count iovcnt is less than zero, expect an EINVAL.
  *
- * USAGE
- *	readv02
+ *  test 4:
+ *  The parameter passed to read is a directory, check if the errno is
+ *  set to EISDIR.
  *
- * HISTORY
- *	07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS
- * 	None
+ *  test 5:
+ *  Read with an invalid file descriptor, and expect an EBADF.
  */
-#include <sys/types.h>
+
 #include <sys/uio.h>
 #include <fcntl.h>
-#include <sys/mman.h>
 #include <memory.h>
-#include <errno.h>
-
-#include "test.h"
-#include "safe_macros.h"
-
-#define	K_1	1024
-#define	M_1	K_1 * K_1
-#define	G_1	M_1 * K_1
-
-#define	NBUFS		4
-#define	CHUNK		64
-#define	MAX_IOVEC	16
-#define DATA_FILE	"readv_data_file"
-
-char buf1[K_1], buf2[K_1], buf3[K_1];
-
-struct iovec rd_iovec[MAX_IOVEC] = {
-	/* iov_base *//* iov_len */
+#include "tst_test.h"
+
+#define K_1     1024
+#define M_1     (K_1 * K_1)
+#define G_1     (M_1 * K_1)
+#define MODES   0700
+
+#define NBUFS           4
+#define CHUNK           64
+#define MAX_IOVEC       16
+
+static int badfd = -1;
+static int fd[4] = {-1, -1, -1, -1};
+static char buf1[K_1], buf2[K_1], buf3[K_1];
+const char *TEST_DIR = "test_dir";
+const char *TEST_FILE[3] = {"file1", "file2", "file3"};
+char *buf_list[NBUFS];
 
-	/* Test case #1 */
+static struct iovec rd_iovec[MAX_IOVEC] = {
 	{buf2, -1},
 	{(buf2 + CHUNK), CHUNK},
 	{(buf2 + CHUNK * 2), CHUNK},
-
-	/* Test case #2 */
 	{(buf2 + CHUNK * 3), G_1},
 	{(buf2 + CHUNK * 4), G_1},
 	{(buf2 + CHUNK * 5), G_1},
-
-	/* Test case #3 */
 	{(caddr_t) - 1, CHUNK},
 	{(buf2 + CHUNK * 6), CHUNK},
 	{(buf2 + CHUNK * 8), CHUNK},
-
-	/* Test case #4 */
-	{(buf2 + CHUNK * 9), CHUNK}
+	{(buf2 + CHUNK * 9), CHUNK},
+	{buf1, K_1}
 };
 
-char f_name[K_1];
-
-int fd[4];
-char *buf_list[NBUFS];
-
-char *TCID = "readv02";
-int TST_TOTAL = 1;
-
-char *bad_addr = 0;
+static struct tcase {
+	int *fd;
+	void *buf;
+	int count;
+	int exp_error;
+} tcases[] = {
+	{&fd[0], rd_iovec, 1, EINVAL},
+	{&fd[1], rd_iovec + 6, 3, EFAULT},
+	{&fd[2], rd_iovec + 10, -1, EINVAL},
+	{&fd[3], rd_iovec + 10, 1, EISDIR},
+	{&badfd, rd_iovec + 9, 3, EBADF},
+};
 
-int init_buffs(char **);
-int fill_mem(char *, int, int);
-long l_seek(int, long, int);
-char *getenv();
-void setup();
-void cleanup();
 
-int main(int ac, char **av)
+void fill_mem(char *c_ptr, int c1, int c2)
 {
-	int lc;
-
-	tst_parse_opts(ac, av, NULL, NULL);
-
-	setup();
+	int count;
 
-	/* The following loop checks looping state if -i option given */
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
+	for (count = 1; count <= K_1 / CHUNK; count++) {
+		if (count & 0x01) /* if odd */
+			memset(c_ptr, c1, CHUNK);
+		else /* if even */
+			memset(c_ptr, c2, CHUNK);
+	}
+	return;
+}
 
-		/* reset tst_count in case we are looping */
-		tst_count = 0;
+void init_buffs(char *pbufs[])
+{
+	int i;
 
-//test1:
-		if (readv(fd[0], rd_iovec, 1) < 0) {
-			if (errno != EINVAL) {
-				tst_resm(TFAIL, "readv() set an illegal errno:"
-					 " expected: EINVAL, got %d", errno);
-			} else {
-				tst_resm(TPASS, "got EINVAL");
-			}
-		} else {
-			tst_resm(TFAIL, "Error: readv returned a positive "
-				 "value");
+	for (i = 0; pbufs[i] != NULL; i++) {
+		switch (i) {
+		case 0:
+		case 1:
+			fill_mem(pbufs[i], 0, 1);
+			break;
+		case 2:
+			fill_mem(pbufs[i], 1, 0);
+			break;
+		default:
+			tst_brk(TBROK, "Error in init_buffs function");
 		}
+	}
+	return;
+}
 
-//test2:
-		l_seek(fd[0], CHUNK * 6, 0);
-		if (readv(fd[0], (rd_iovec + 6), 3) < 0) {
-			if (errno != EFAULT) {
-				tst_resm(TFAIL, "expected errno = EFAULT, "
-					 "got %d", errno);
-			} else {
-				tst_resm(TPASS, "got EFAULT");
-			}
-			if (memcmp((buf_list[0] + CHUNK * 6),
-				   (buf_list[1] + CHUNK * 6), CHUNK * 3) != 0) {
-				tst_resm(TFAIL, "Error: readv() partially "
-					 "overlaid buf[2]");
-			}
-		} else {
-			tst_resm(TFAIL, "Error: readv returned a positive "
-				 "value");
-		}
+static void verify_readv(unsigned int n)
+{
+	struct tcase *tc = &tcases[n];
 
-//test3:
-		if (readv(fd[1], (rd_iovec + 9), 1) < 0) {
-			if (errno != EBADF) {
-				tst_resm(TFAIL, "expected errno = EBADF, "
-					 "got %d", errno);
-			} else {
-				tst_resm(TPASS, "got EBADF");
-			}
-		} else {
-			tst_resm(TFAIL, "Error: readv returned a positive "
-				 "value");
-		}
+	TST_EXP_FAIL2(readv(*tc->fd, tc->buf, tc->count), tc->exp_error,
+		"readv(%d, %p, %d)", *tc->fd, tc->buf, tc->count);
 
-//test4:
-		l_seek(fd[0], CHUNK * 10, 0);
-		if (readv(fd[0], (rd_iovec + 10), -1) < 0) {
-			if (errno != EINVAL) {
-				tst_resm(TFAIL, "expected errno = EINVAL, "
-					 "got %d", errno);
-			} else {
-				tst_resm(TPASS, "got EINVAL");
-			}
-		} else {
-			tst_resm(TFAIL, "Error: readv returned a positive "
-				 "value");
+	if (tc->exp_error == EFAULT) {
+		if (memcmp((buf_list[0] + CHUNK * 6),
+			(buf_list[1] + CHUNK * 6), CHUNK * 3)) {
+		    tst_res(TFAIL, "Error: readv() partially overlaid buf[2]");
 		}
-
 	}
-	close(fd[0]);
-	close(fd[1]);
-	cleanup();
-	tst_exit();
-
 }
 
-/*
- * setup() - performs all ONE TIME setup for this test.
- */
 void setup(void)
 {
-	int nbytes;
-
-	tst_sig(NOFORK, DEF_HANDLER, cleanup);
-
-	TEST_PAUSE;
-
-	/* make a temporary directory and cd to it */
-	tst_tmpdir();
+	int i;
 
 	buf_list[0] = buf1;
 	buf_list[1] = buf2;
@@ -201,84 +133,37 @@  void setup(void)
 
 	init_buffs(buf_list);
 
-	sprintf(f_name, "%s.%d", DATA_FILE, getpid());
+	for (i = 0; i < 3; i++) {
+		fd[i] = SAFE_OPEN(TEST_FILE[i], O_WRONLY | O_CREAT, 0666);
+		SAFE_WRITE(1, fd[i], buf_list[2], K_1);
 
-	if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
-		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
-			 "errno = %d", f_name, errno);
-	} else {
-		if ((nbytes = write(fd[0], buf_list[2], K_1)) != K_1) {
-			tst_brkm(TBROK, cleanup, "write failed: nbytes "
-				 "= %d " "errno = %d", nbytes, errno);
-		}
-	}
+		SAFE_CLOSE(fd[i]);
 
-	SAFE_CLOSE(cleanup, fd[0]);
-
-	if ((fd[0] = open(f_name, O_RDONLY, 0666)) < 0) {
-		tst_brkm(TBROK, cleanup, "open failed: fname = %s, "
-			 "errno = %d", f_name, errno);
+		fd[i] = SAFE_OPEN(TEST_FILE[i], O_RDONLY, 0666);
 	}
+	SAFE_LSEEK(fd[1], CHUNK * 6, 0);
+	SAFE_LSEEK(fd[2], CHUNK * 10, 0);
 
-	fd[1] = -1;		/* Invalid file descriptor */
+	rd_iovec[6].iov_base = tst_get_bad_addr(NULL);
 
-	bad_addr = mmap(0, 1, PROT_NONE,
-			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
-	if (bad_addr == MAP_FAILED) {
-		tst_brkm(TBROK, cleanup, "mmap failed");
-	}
-	rd_iovec[6].iov_base = bad_addr;
+	SAFE_MKDIR(TEST_DIR, MODES);
+	fd[3] = SAFE_OPEN(TEST_DIR, O_RDONLY);
 }
 
-/*
- * cleanup() - performs all ONE TIME cleanup for this test at
- *	       completion or premature exit.
- */
-void cleanup(void)
-{
-	SAFE_UNLINK(NULL, f_name);
-	tst_rmdir();
-
-}
-
-int init_buffs(char *pbufs[])
+static void cleanup(void)
 {
 	int i;
 
-	for (i = 0; pbufs[i] != NULL; i++) {
-		switch (i) {
-		case 0:
-		 /*FALLTHROUGH*/ case 1:
-			fill_mem(pbufs[i], 0, 1);
-			break;
-
-		case 2:
-			fill_mem(pbufs[i], 1, 0);
-			break;
-
-		default:
-			tst_brkm(TBROK, cleanup, "Error in init_buffs()");
-		}
-	}
-	return 0;
-}
-
-int fill_mem(char *c_ptr, int c1, int c2)
-{
-	int count;
-
-	for (count = 1; count <= K_1 / CHUNK; count++) {
-		if (count & 0x01) {	/* if odd */
-			memset(c_ptr, c1, CHUNK);
-		} else {	/* if even */
-			memset(c_ptr, c2, CHUNK);
-		}
+	for (i = 0; i < 4; i++) {
+		if (fd[i] > 0)
+			SAFE_CLOSE(fd[i]);
 	}
-	return 0;
 }
 
-long l_seek(int fdesc, long offset, int whence)
-{
-	SAFE_LSEEK(cleanup, fdesc, offset, whence);
-	return 0;
-}
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(tcases),
+	.needs_tmpdir = 1,
+	.setup = setup,
+	.cleanup = cleanup,
+	.test = verify_readv,
+};
diff --git a/testcases/kernel/syscalls/readv/readv03.c b/testcases/kernel/syscalls/readv/readv03.c
deleted file mode 100644
index 8f5cddf..0000000
--- a/testcases/kernel/syscalls/readv/readv03.c
+++ /dev/null
@@ -1,53 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) Bull S.A. 2001
- * Copyright (c) International Business Machines  Corp., 2001
- * 05/2002 Ported by Jacky Malcles
- */
-
-/*\
- * [Description]
- *
- * Testcase to check EISDIR error when fd refers to a directory.
- */
-
-#include <sys/uio.h>
-#include <fcntl.h>
-#include "tst_test.h"
-
-#define K_1     1024
-#define MODES   S_IRWXU
-
-static char buf1[K_1];
-
-static struct iovec rd_iovec[1] = {
-        {buf1, K_1}
-};
-
-const char *TEST_DIR = "alpha";
-static int fd;
-
-static void verify_readv(void)
-{
-        TST_EXP_FAIL2(readv(fd, rd_iovec, 1), EISDIR,
-                     "readv() got EISDIR");
-}
-
-void setup(void)
-{
-        SAFE_MKDIR(TEST_DIR, MODES);
-        fd = SAFE_OPEN(TEST_DIR, O_RDONLY);
-}
-
-static void cleanup(void)
-{
-        if (fd > 0)
-                SAFE_CLOSE(fd);
-}
-
-static struct tst_test test = {
-        .needs_tmpdir = 1,
-        .setup = setup,
-        .cleanup = cleanup,
-        .test_all = verify_readv,
-};