glibc/misc/tst-preadvwritev2-common.c
Stafford Horne 70f560fc22 misc: Add support for Linux uio.h RWF_NOAPPEND flag
In Linux 6.9 a new flag is added to allow for Per-io operations to
disable append mode even if a file was opened with the flag O_APPEND.
This is done with the new RWF_NOAPPEND flag.

This caused two test failures as these tests expected the flag 0x00000020
to be unused.  Adding the flag definition now fixes these tests on Linux
6.9 (v6.9-rc1).

  FAIL: misc/tst-preadvwritev2
  FAIL: misc/tst-preadvwritev64v2

This patch adds the flag, adjusts the test and adds details to
documentation.

Link: https://lore.kernel.org/all/20200831153207.GO3265@brightrain.aerifal.cx/
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 3db9d208dd)
2024-05-29 13:51:32 +02:00

127 lines
4.2 KiB
C

/* Common function for preadv2 and pwritev2 tests.
Copyright (C) 2017-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <limits.h>
#include <support/check.h>
#ifndef RWF_HIPRI
# define RWF_HIPRI 0
#endif
#ifndef RWF_DSYNC
# define RWF_DSYNC 0
#endif
#ifndef RWF_SYNC
# define RWF_SYNC 0
#endif
#ifndef RWF_NOWAIT
# define RWF_NOWAIT 0
#endif
#ifndef RWF_APPEND
# define RWF_APPEND 0
#endif
#ifndef RWF_NOAPPEND
# define RWF_NOAPPEND 0
#endif
#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
| RWF_APPEND | RWF_NOAPPEND)
/* Generic uio_lim.h does not define IOV_MAX. */
#ifndef IOV_MAX
# define IOV_MAX 1024
#endif
static void
do_test_with_invalid_fd (void)
{
char buf[256];
struct iovec iov = { buf, sizeof buf };
/* Check with flag being 0 to use the fallback code which calls pwritev
or writev. */
TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1);
TEST_COMPARE (errno, EBADF);
TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1);
TEST_COMPARE (errno, EBADF);
/* Same tests as before but with flags being different than 0. Since
there is no emulation for any flag value, fallback code returns
ENOTSUP. This is different running on a kernel with preadv2/pwritev2
support, where EBADF is returned). */
TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
}
static void
do_test_with_invalid_iov (void)
{
{
char buf[256];
struct iovec iov;
iov.iov_base = buf;
iov.iov_len = (size_t)SSIZE_MAX + 1;
TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1);
TEST_COMPARE (errno, EINVAL);
TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1);
TEST_COMPARE (errno, EINVAL);
/* Same as for invalid file descriptor tests, emulation fallback
first checks for flag value and return ENOTSUP. */
TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
}
{
/* An invalid iovec buffer should trigger an invalid memory access
or an error (Linux for instance returns EFAULT). */
struct iovec iov[IOV_MAX+1] = { 0 };
TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
}
}
static void
do_test_with_invalid_flags (void)
{
/* Set the next bit from the mask of all supported flags. */
int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2;
invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag);
char buf[32];
const struct iovec vec = { .iov_base = buf, .iov_len = sizeof (buf) };
if (preadv2 (temp_fd, &vec, 1, 0, invalid_flag) != -1)
FAIL_EXIT1 ("preadv2 did not fail with an invalid flag");
if (errno != ENOTSUP)
FAIL_EXIT1 ("preadv2 failure did not set errno to ENOTSUP (%d)", errno);
/* This might fail for compat syscall (32 bits running on 64 bits kernel)
due a kernel issue. */
if (pwritev2 (temp_fd, &vec, 1, 0, invalid_flag) != -1)
FAIL_EXIT1 ("pwritev2 did not fail with an invalid flag");
if (errno != ENOTSUP)
FAIL_EXIT1 ("pwritev2 failure did not set errno to ENOTSUP (%d)", errno);
}