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 |
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, > +};
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 --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, -};
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