getrlimit/getrlimit03: new test for underlying syscall variants
PATCH 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
Depending on the architecture, Linux provides up to three syscalls that have been used to implement getrlimit(2) in different libc implementations. These syscalls differ in the size and signedness of rlim_t.
This test compares the results returned by all three syscalls, confirming that they either match or were appropriately capped at the respective RLIM_INFINITY constant.
--- .../kernel/syscalls/getrlimit/getrlimit03.c | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 testcases/kernel/syscalls/getrlimit/getrlimit03.c
testcases/kernel/syscalls/getrlimit/getrlimit03.c new file +195 -0
@@ -0,0 +1,195 @@ +/* +* Copyright (c) 2018 Google, Inc. +* +* 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, see <http://www.gnu.org/licenses/>. +*/ + +/** +* Architectures may provide up to three syscalls that have been used to +* implement getrlimit(2) in different libc implementations. These syscalls +* differ in the size and signedness of rlim_t: +* +* - __NR_getrlimit uses long or unsigned long, depending on the +* architecture +* +* - __NR_ugetrlimit uses unsigned long, and only exists on +* architectures where __NR_getrlimit is signed +* +* - __NR_prlimit64 uses uint64_t +* +* This test compares the results returned by all three syscalls, confirming +* that they either match or were appropriately capped at the respective +* RLIM_INFINITY constant. +*/ + +#include <inttypes.h> +#include <stdint.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include "tst_test.h" +#include "lapi/syscalls.h" + +/** +* Linux provides an "old" getrlimit syscall handler that uses signed long, +* and a "new" getrlimit syscall handler that uses unsigned long. +* +* The underlying syscall names vary across architectures, depending on whether +* the architecture predates the "new" handler. For clarity, this test +* will call them getrlimit_long and getlimit_ulong internally. +*/ +#define SIGNED_GETRLIMIT (__NR_ugetrlimit != __LTP__NR_INVALID_SYSCALL) +#if SIGNED_GETRLIMIT +#define __NR_getrlimit_ulong __NR_ugetrlimit +#define __NR_getrlimit_ulong_str "__NR_ugetrlimit" +#else +#define __NR_getrlimit_ulong __NR_getrlimit +#define __NR_getrlimit_ulong_str "__NR_getrlimit" +#endif + +struct rlimit64 { +uint64_t rlim_cur; +uint64_t rlim_max; +}; +const uint64_t RLIM_INFINITY_U64 =UINT64_MAX ; + +static int getrlimit_u64 (int resource,struct rlimit64 *rlim) +{ +return syscall (__NR_prlimit64,0 , resource,NULL , rlim); +} + +struct rlimit_ulong { +unsigned long rlim_cur; +unsigned long rlim_max; +}; +const unsigned long RLIM_INFINITY_UL =ULONG_MAX ; + +static int getrlimit_ulong (int resource,struct rlimit_ulong *rlim) +{ +return syscall (__NR_getrlimit_ulong, resource, rlim); +} + +#if SIGNED_GETRLIMIT +struct rlimit_long { +long rlim_cur; +long rlim_max; +}; +const long RLIM_INFINITY_L =LONG_MAX ; + +static int getrlimit_long (int resource,struct rlimit_long *rlim) +{ +return syscall (__NR_getrlimit, resource, rlim); +} +#endif + +static int compare_retval (int resource,int ret_u64,int errno_u64, +int ret_other,int errno_other, +const char *other_syscall) +{ +if (ret_u64 != ret_other || errno_u64 != errno_other) { +tst_res (TFAIL ,"__NR_prlimit64(%d) returned %d (%s) but %s(%d) returned %d (%s)" , + resource, ret_u64,tst_strerrno (errno_u64), + other_syscall, resource, ret_other, +tst_strerrno (errno_other)); +return -1 ; + } + +return 0 ; +} + +static int compare_u64_ulong (int resource,uint64_t val_u64, +unsigned long val_ul,const char *kind) +{ +if ((val_u64 >RLIM_INFINITY_UL && val_ul !=RLIM_INFINITY_UL ) || + (val_u64 <=RLIM_INFINITY_UL && val_ul != val_u64)) { +tst_res (TFAIL ,"__NR_prlimit64(%d) had %s = %" PRIx64" but " __NR_getrlimit_ulong_str"(%d) had %s = %lx" , + resource, kind, val_u64, + resource, kind, val_ul); +return -1 ; + } + +return 0 ; +} + +#if SIGNED_GETRLIMIT +static int compare_u64_long (int resource,uint64_t val_u64,long val_l, +const char *kind) +{ +if ((val_u64 > (uint64_t )RLIM_INFINITY_L && val_l !=RLIM_INFINITY_L ) || + (val_u64 <= (uint64_t )RLIM_INFINITY_L && val_l != (long )val_u64)) { +tst_res (TFAIL ,"__NR_prlimit64(%d) had %s = %" PRIx64" but __NR_getrlimit(%d) had %s = %lx" , + resource, kind, val_u64, + resource, kind, val_l); +return -1 ; + } + +return 0 ; +} +#endif + +static void run (unsigned int resource) +{ +struct rlimit64 rlim_u64; +int ret_u64; +int errno_u64; + +struct rlimit_ulong rlim_ul; +int ret_ul; +int errno_ul; + +#if SIGNED_GETRLIMIT +struct rlimit_long rlim_l; +int ret_l; +int errno_l; +#endif + + errno =0 ; + ret_u64 =getrlimit_u64 (resource, &rlim_u64); + errno_u64 = errno; + + errno =0 ; + ret_ul =getrlimit_ulong (resource, &rlim_ul); + errno_ul = errno; + +if (compare_retval (resource, ret_u64, errno_u64, ret_ul, errno_ul, + __NR_getrlimit_ulong_str) || +compare_u64_ulong (resource, rlim_u64.rlim_cur, rlim_ul.rlim_cur, +"rlim_cur" ) || +compare_u64_ulong (resource, rlim_u64.rlim_max, rlim_ul.rlim_max, +"rlim_max" )) +return ; + +#if SIGNED_GETRLIMIT + errno =0 ; + ret_l =getrlimit_long (resource, &rlim_l); + errno_l = errno; + +if (compare_retval (resource, ret_u64, errno_u64, ret_l, errno_l, +"__NR_getrlimit" ) || +compare_u64_long (resource, rlim_u64.rlim_cur, rlim_l.rlim_cur, +"rlim_cur" ) || +compare_u64_long (resource, rlim_u64.rlim_max, rlim_l.rlim_max, +"rlim_max" )) +return ; +#endif + +tst_res (TPASS ,"getrlimit(%u) was consistent during all syscalls" , + resource); +} + +static struct tst_test test = { + .tcnt =RLIM_NLIMITS , + .test = run, +}; +
Signature · 1 line
2.19.1.930.g4563a0d9d0-goog
PATCH 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
----- Original Message -----
<snip>
testcases/kernel/syscalls/getrlimit/getrlimit03.c line 69
Quoted 5 lines
testcases/kernel/syscalls/getrlimit/getrlimit03.c new file +5
-0+const uint64_t RLIM_INFINITY_U64 =UINT64_MAX ; + +static int getrlimit_u64 (int resource,struct rlimit64 *rlim) +{ +return syscall (__NR_prlimit64,0 , resource,NULL , rlim);
Hi,
(Likely an issue for old distro kernels, but)
consider using ltp_syscall here, or in setup(). Syscall __NR defines come from LTP, so those will be always present, but syscall can still be unsupported by kernel, so test can end up comparing with 'ENOSYS'.
Regards,
Jan
PATCH 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
Hi!
Quoted 10 lines
testcases/kernel/syscalls/getrlimit/getrlimit03.c line 69
Quoted 5 lines
testcases/kernel/syscalls/getrlimit/getrlimit03.c new file +5
-0+const uint64_t RLIM_INFINITY_U64 =UINT64_MAX ; + +static int getrlimit_u64 (int resource,struct rlimit64 *rlim) +{ +return syscall (__NR_prlimit64,0 , resource,NULL , rlim);Hi,
(Likely an issue for old distro kernels, but)
consider usingltp_syscallhere, or insetup(). Syscall__NRdefines
^
That would be tst_syscall() for new tst_test.h library
Quoted 2 lines
come from LTP, so those will be always present, but syscall can still be unsupported by kernel, so test can end up comparing with 'ENOSYS'.
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
Quoted 9 lines · Cyril Hrubis
Hi!
Quoted 8 lines
testcases/kernel/syscalls/getrlimit/getrlimit03.c line 69
Quoted 5 lines
testcases/kernel/syscalls/getrlimit/getrlimit03.c new file +5
-0+const uint64_t RLIM_INFINITY_U64 =UINT64_MAX ; + +static int getrlimit_u64 (int resource,struct rlimit64 *rlim) +{ +return syscall (__NR_prlimit64,0 , resource,NULL , rlim);Hi,
Quoted 9 lines
Quoted 2 lines
(Likely an issue for old distro kernels, but)
consider usingltp_syscallhere, or insetup(). Syscall__NRdefines^
That would betst_syscall()for newtst_test.hlibraryQuoted 2 lines
come from LTP, so those will be always present, but syscall can still be unsupported by kernel, so test can end up comparing with 'ENOSYS'.
Thanks for the feedback. I'll send a v2 with this change shortly.
PATCH v2 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
In reply to Cyril HrubisDepending on the architecture, Linux provides up to three syscalls that have been used to implement getrlimit(2) in different libc implementations. These syscalls differ in the size and signedness of rlim_t.
This test compares the results returned by all three syscalls, confirming that they either match or were appropriately capped at the respective RLIM_INFINITY constant.
---
v2: use tst_syscall() to correctly handle kernels that don't have the prlimit64 syscall
.../kernel/syscalls/getrlimit/getrlimit03.c | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 testcases/kernel/syscalls/getrlimit/getrlimit03.c
testcases/kernel/syscalls/getrlimit/getrlimit03.c new file +195 -0
@@ -0,0 +1,195 @@ +/* +* Copyright (c) 2018 Google, Inc. +* +* 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, see <http://www.gnu.org/licenses/>. +*/ + +/** +* Architectures may provide up to three syscalls that have been used to +* implement getrlimit(2) in different libc implementations. These syscalls +* differ in the size and signedness of rlim_t: +* +* - __NR_getrlimit uses long or unsigned long, depending on the +* architecture +* +* - __NR_ugetrlimit uses unsigned long, and only exists on +* architectures where __NR_getrlimit is signed +* +* - __NR_prlimit64 uses uint64_t +* +* This test compares the results returned by all three syscalls, confirming +* that they either match or were appropriately capped at the respective +* RLIM_INFINITY constant. +*/ + +#include <inttypes.h> +#include <stdint.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include "tst_test.h" +#include "lapi/syscalls.h" + +/** +* Linux provides an "old" getrlimit syscall handler that uses signed long, +* and a "new" getrlimit syscall handler that uses unsigned long. +* +* The underlying syscall names vary across architectures, depending on whether +* the architecture predates the "new" handler. For clarity, this test +* will call them getrlimit_long and getlimit_ulong internally. +*/ +#define SIGNED_GETRLIMIT (__NR_ugetrlimit != __LTP__NR_INVALID_SYSCALL) +#if SIGNED_GETRLIMIT +#define __NR_getrlimit_ulong __NR_ugetrlimit +#define __NR_getrlimit_ulong_str "__NR_ugetrlimit" +#else +#define __NR_getrlimit_ulong __NR_getrlimit +#define __NR_getrlimit_ulong_str "__NR_getrlimit" +#endif + +struct rlimit64 { +uint64_t rlim_cur; +uint64_t rlim_max; +}; +const uint64_t RLIM_INFINITY_U64 =UINT64_MAX ; + +static int getrlimit_u64 (int resource,struct rlimit64 *rlim) +{ +return tst_syscall (__NR_prlimit64,0 , resource,NULL , rlim); +} + +struct rlimit_ulong { +unsigned long rlim_cur; +unsigned long rlim_max; +}; +const unsigned long RLIM_INFINITY_UL =ULONG_MAX ; + +static int getrlimit_ulong (int resource,struct rlimit_ulong *rlim) +{ +return syscall (__NR_getrlimit_ulong, resource, rlim); +} + +#if SIGNED_GETRLIMIT +struct rlimit_long { +long rlim_cur; +long rlim_max; +}; +const long RLIM_INFINITY_L =LONG_MAX ; + +static int getrlimit_long (int resource,struct rlimit_long *rlim) +{ +return syscall (__NR_getrlimit, resource, rlim); +} +#endif + +static int compare_retval (int resource,int ret_u64,int errno_u64, +int ret_other,int errno_other, +const char *other_syscall) +{ +if (ret_u64 != ret_other || errno_u64 != errno_other) { +tst_res (TFAIL ,"__NR_prlimit64(%d) returned %d (%s) but %s(%d) returned %d (%s)" , + resource, ret_u64,tst_strerrno (errno_u64), + other_syscall, resource, ret_other, +tst_strerrno (errno_other)); +return -1 ; + } + +return 0 ; +} + +static int compare_u64_ulong (int resource,uint64_t val_u64, +unsigned long val_ul,const char *kind) +{ +if ((val_u64 >RLIM_INFINITY_UL && val_ul !=RLIM_INFINITY_UL ) || + (val_u64 <=RLIM_INFINITY_UL && val_ul != val_u64)) { +tst_res (TFAIL ,"__NR_prlimit64(%d) had %s = %" PRIx64" but " __NR_getrlimit_ulong_str"(%d) had %s = %lx" , + resource, kind, val_u64, + resource, kind, val_ul); +return -1 ; + } + +return 0 ; +} + +#if SIGNED_GETRLIMIT +static int compare_u64_long (int resource,uint64_t val_u64,long val_l, +const char *kind) +{ +if ((val_u64 > (uint64_t )RLIM_INFINITY_L && val_l !=RLIM_INFINITY_L ) || + (val_u64 <= (uint64_t )RLIM_INFINITY_L && val_l != (long )val_u64)) { +tst_res (TFAIL ,"__NR_prlimit64(%d) had %s = %" PRIx64" but __NR_getrlimit(%d) had %s = %lx" , + resource, kind, val_u64, + resource, kind, val_l); +return -1 ; + } + +return 0 ; +} +#endif + +static void run (unsigned int resource) +{ +struct rlimit64 rlim_u64; +int ret_u64; +int errno_u64; + +struct rlimit_ulong rlim_ul; +int ret_ul; +int errno_ul; + +#if SIGNED_GETRLIMIT +struct rlimit_long rlim_l; +int ret_l; +int errno_l; +#endif + + errno =0 ; + ret_u64 =getrlimit_u64 (resource, &rlim_u64); + errno_u64 = errno; + + errno =0 ; + ret_ul =getrlimit_ulong (resource, &rlim_ul); + errno_ul = errno; + +if (compare_retval (resource, ret_u64, errno_u64, ret_ul, errno_ul, + __NR_getrlimit_ulong_str) || +compare_u64_ulong (resource, rlim_u64.rlim_cur, rlim_ul.rlim_cur, +"rlim_cur" ) || +compare_u64_ulong (resource, rlim_u64.rlim_max, rlim_ul.rlim_max, +"rlim_max" )) +return ; + +#if SIGNED_GETRLIMIT + errno =0 ; + ret_l =getrlimit_long (resource, &rlim_l); + errno_l = errno; + +if (compare_retval (resource, ret_u64, errno_u64, ret_l, errno_l, +"__NR_getrlimit" ) || +compare_u64_long (resource, rlim_u64.rlim_cur, rlim_l.rlim_cur, +"rlim_cur" ) || +compare_u64_long (resource, rlim_u64.rlim_max, rlim_l.rlim_max, +"rlim_max" )) +return ; +#endif + +tst_res (TPASS ,"getrlimit(%u) was consistent during all syscalls" , + resource); +} + +static struct tst_test test = { + .tcnt =RLIM_NLIMITS , + .test = run, +}; +
Signature · 1 line
2.19.1.930.g4563a0d9d0-goog
PATCH v2 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
----- Original Message -----
Quoted 10 lines
Depending on the architecture, Linux provides up to three syscalls that have been used to implement getrlimit(2) in different libc implementations. These syscalls differ in the size and signedness of
rlim_t.This test compares the results returned by all three syscalls, confirming that they either match or were appropriately capped at the respective
RLIM_INFINITYconstant.Signed-off-by Greg Hackmann <[email protected]>
Looks good to me, worked fine across number of old/new RHEL distros.
Regards,
Jan
PATCH v2 1/1 getrlimit/getrlimit03: new test for underlying syscall variants
In reply to Greg HackmannHi Greg,
Quoted 11 lines
Depending on the architecture, Linux provides up to three syscalls that have been used to implement getrlimit(2) in different libc implementations. These syscalls differ in the size and signedness of
rlim_t.This test compares the results returned by all three syscalls, confirming that they either match or were appropriately capped at the respective
RLIM_INFINITYconstant.Signed-off-by Greg Hackmann <[email protected]>---
Thanks for your patch, pushed with minor GPL related change (replaced GPL text with SPDX-License-Identifier).
Kind regards,
Petr