Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rseq: Extend struct rseq with per-memory-map concurrency ID

If a memory map has fewer threads than there are cores on the system, or
is limited to run on few cores concurrently through sched affinity or
cgroup cpusets, the concurrency IDs will be values close to 0, thus
allowing efficient use of user-space memory for per-cpu data structures.

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-9-mathieu.desnoyers@efficios.com

authored by

Mathieu Desnoyers and committed by
Peter Zijlstra
f7b01bb0 af7f588d

+19 -1
+9
include/uapi/linux/rseq.h
··· 140 140 __u32 node_id; 141 141 142 142 /* 143 + * Restartable sequences mm_cid field. Updated by the kernel. Read by 144 + * user-space with single-copy atomicity semantics. This field should 145 + * only be read by the thread which registered this data structure. 146 + * Aligned on 32-bit. Contains the current thread's concurrency ID 147 + * (allocated uniquely within a memory map). 148 + */ 149 + __u32 mm_cid; 150 + 151 + /* 143 152 * Flexible array member at end of structure, after last feature field. 144 153 */ 145 154 char end[];
+10 -1
kernel/rseq.c
··· 90 90 struct rseq __user *rseq = t->rseq; 91 91 u32 cpu_id = raw_smp_processor_id(); 92 92 u32 node_id = cpu_to_node(cpu_id); 93 + u32 mm_cid = task_mm_cid(t); 93 94 95 + WARN_ON_ONCE((int) mm_cid < 0); 94 96 if (!user_write_access_begin(rseq, t->rseq_len)) 95 97 goto efault; 96 98 unsafe_put_user(cpu_id, &rseq->cpu_id_start, efault_end); 97 99 unsafe_put_user(cpu_id, &rseq->cpu_id, efault_end); 98 100 unsafe_put_user(node_id, &rseq->node_id, efault_end); 101 + unsafe_put_user(mm_cid, &rseq->mm_cid, efault_end); 99 102 /* 100 103 * Additional feature fields added after ORIG_RSEQ_SIZE 101 104 * need to be conditionally updated only if ··· 116 113 117 114 static int rseq_reset_rseq_cpu_node_id(struct task_struct *t) 118 115 { 119 - u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED, node_id = 0; 116 + u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED, node_id = 0, 117 + mm_cid = 0; 120 118 121 119 /* 122 120 * Reset cpu_id_start to its initial state (0). ··· 135 131 * Reset node_id to its initial state (0). 136 132 */ 137 133 if (put_user(node_id, &t->rseq->node_id)) 134 + return -EFAULT; 135 + /* 136 + * Reset mm_cid to its initial state (0). 137 + */ 138 + if (put_user(mm_cid, &t->rseq->mm_cid)) 138 139 return -EFAULT; 139 140 /* 140 141 * Additional feature fields added after ORIG_RSEQ_SIZE