selftests/rseq: Implement rseq numa node id field selftest

Test the NUMA node id extension rseq field. Compare it against the value
returned by the getcpu(2) system call while pinned on a specific core.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20221122203932.231377-7-mathieu.desnoyers@efficios.com
This commit is contained in:
Mathieu Desnoyers 2022-11-22 15:39:08 -05:00 committed by Peter Zijlstra
parent 03f5c0272d
commit 99babd04b2
4 changed files with 58 additions and 0 deletions

View File

@ -22,6 +22,8 @@ void test_cpu_pointer(void)
CPU_ZERO(&test_affinity);
for (i = 0; i < CPU_SETSIZE; i++) {
if (CPU_ISSET(i, &affinity)) {
int node;
CPU_SET(i, &test_affinity);
sched_setaffinity(0, sizeof(test_affinity),
&test_affinity);
@ -29,6 +31,8 @@ void test_cpu_pointer(void)
assert(rseq_current_cpu() == i);
assert(rseq_current_cpu_raw() == i);
assert(rseq_cpu_start() == i);
node = rseq_fallback_current_node();
assert(rseq_current_node_id() == node);
CPU_CLR(i, &test_affinity);
}
}

View File

@ -147,6 +147,14 @@ struct rseq_abi {
*/
__u32 flags;
/*
* Restartable sequences node_id field. Updated by the kernel. Read by
* user-space with single-copy atomicity semantics. This field should
* only be read by the thread which registered this data structure.
* Aligned on 32-bit. Contains the current NUMA node ID.
*/
__u32 node_id;
/*
* Flexible array member at end of structure, after last feature field.
*/

View File

@ -79,6 +79,11 @@ static int sys_rseq(struct rseq_abi *rseq_abi, uint32_t rseq_len,
return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
}
static int sys_getcpu(unsigned *cpu, unsigned *node)
{
return syscall(__NR_getcpu, cpu, node, NULL);
}
int rseq_available(void)
{
int rc;
@ -201,3 +206,16 @@ int32_t rseq_fallback_current_cpu(void)
}
return cpu;
}
int32_t rseq_fallback_current_node(void)
{
uint32_t cpu_id, node_id;
int ret;
ret = sys_getcpu(&cpu_id, &node_id);
if (ret) {
perror("sys_getcpu()");
return ret;
}
return (int32_t) node_id;
}

View File

@ -20,6 +20,15 @@
#include "rseq-abi.h"
#include "compiler.h"
#ifndef rseq_sizeof_field
#define rseq_sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
#endif
#ifndef rseq_offsetofend
#define rseq_offsetofend(TYPE, MEMBER) \
(offsetof(TYPE, MEMBER) + rseq_sizeof_field(TYPE, MEMBER))
#endif
/*
* Empty code injection macros, override when testing.
* It is important to consider that the ASM injection macros need to be
@ -128,6 +137,11 @@ int rseq_unregister_current_thread(void);
*/
int32_t rseq_fallback_current_cpu(void);
/*
* Restartable sequence fallback for reading the current node number.
*/
int32_t rseq_fallback_current_node(void);
/*
* Values returned can be either the current CPU number, -1 (rseq is
* uninitialized), or -2 (rseq initialization has failed).
@ -163,6 +177,20 @@ static inline uint32_t rseq_current_cpu(void)
return cpu;
}
static inline bool rseq_node_id_available(void)
{
return (int) rseq_feature_size >= rseq_offsetofend(struct rseq_abi, node_id);
}
/*
* Current NUMA node number.
*/
static inline uint32_t rseq_current_node_id(void)
{
assert(rseq_node_id_available());
return RSEQ_ACCESS_ONCE(rseq_get_abi()->node_id);
}
static inline void rseq_clear_rseq_cs(void)
{
RSEQ_WRITE_ONCE(rseq_get_abi()->rseq_cs.arch.ptr, 0);