Two RSEQ fixes:
- Fix overly spread-out RSEQ concurrency ID allocation pattern that regressed certain workloads. - Fix RSEQ registration syscall behavior on -EFAULT errors when CONFIG_DEBUG_RSEQ=y. (This debug option is disabled on most distributions.) Signed-off-by: Ingo Molnar <mingo@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAme52CARHG1pbmdvQGtl cm5lbC5vcmcACgkQEnMQ0APhK1jKog//cK7PqMRscu7ba95pgRpaL2nn1yuYRGLR I9wqZp1h8Lr8DxxYX48hKDkX8W+zZiJ9fIYm7dWVMNlQt2/SsZIwmd8M6XZlkdJW Okn7xgMA7lyTR9AEtELhxon/lrqYmCP3KF7yfp7Kb/yggbKoi7f7sxHg1PX11Ff0 2FUZGXyLtP3BTyCRKXoMxiegj/ZmE/rhY5XWpx8hATFZRATOwaw2uE4cnOuZiL1k zD6pAcQJGbbqNvm7VMlzjiJZ+a4SSuslHUaP+3zoJ0PJSpd+4jbPPw+w0jxm+xeg Sn/1WDEE/xtEKC1cujlibGOww5RwOVrmNWpDz5Lg1vjICio5TF568HMZTMZBoz5s P4VWFQgM+KtsUgxRjODMQ8NbHwgZKPHAKlF6f3TH0IfZk233EL29AOYwiub8sLNS yK3wFEtj+h0eXU7z6D6Cdx3mUN5dYq1TG+M36WtXrFTkThy41ep8TE176aEjf4j7 ZZcIAf9vO04xSmKeRSbcvylZrHvNtfBjdl+ZhYnhqImPsWCBnmxd0/J3qlr1AUxZ 0qo9gsngf5tgZYEr62/Fbyoa/Rrk2jbKMPl6ecOg3g+bk8Gv1y4R+ahegR3X1yWb 8cXJ51AuH/HQ0NBzhOj/vgEkPESE+Y409wSPEoW/wZGKPCJRC+U9RM9hTSs06qJB c7yKwFwIy1Y= =CuyA -----END PGP SIGNATURE----- Merge tag 'sched-urgent-2025-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull rseq fixes from Ingo Molnar: - Fix overly spread-out RSEQ concurrency ID allocation pattern that regressed certain workloads - Fix RSEQ registration syscall behavior on -EFAULT errors when CONFIG_DEBUG_RSEQ=y (This debug option is disabled on most distributions) * tag 'sched-urgent-2025-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: rseq: Fix rseq registration with CONFIG_DEBUG_RSEQ sched: Compact RSEQ concurrency IDs with reduced threads and affinity
This commit is contained in:
commit
8b82c18bf9
3 changed files with 34 additions and 9 deletions
|
@ -875,10 +875,11 @@ struct mm_struct {
|
||||||
*/
|
*/
|
||||||
unsigned int nr_cpus_allowed;
|
unsigned int nr_cpus_allowed;
|
||||||
/**
|
/**
|
||||||
* @max_nr_cid: Maximum number of concurrency IDs allocated.
|
* @max_nr_cid: Maximum number of allowed concurrency
|
||||||
|
* IDs allocated.
|
||||||
*
|
*
|
||||||
* Track the highest number of concurrency IDs allocated for the
|
* Track the highest number of allowed concurrency IDs
|
||||||
* mm.
|
* allocated for the mm.
|
||||||
*/
|
*/
|
||||||
atomic_t max_nr_cid;
|
atomic_t max_nr_cid;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -507,9 +507,6 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!access_ok(rseq, rseq_len))
|
if (!access_ok(rseq, rseq_len))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
current->rseq = rseq;
|
|
||||||
current->rseq_len = rseq_len;
|
|
||||||
current->rseq_sig = sig;
|
|
||||||
#ifdef CONFIG_DEBUG_RSEQ
|
#ifdef CONFIG_DEBUG_RSEQ
|
||||||
/*
|
/*
|
||||||
* Initialize the in-kernel rseq fields copy for validation of
|
* Initialize the in-kernel rseq fields copy for validation of
|
||||||
|
@ -521,6 +518,14 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
|
||||||
get_user(rseq_kernel_fields(current)->mm_cid, &rseq->mm_cid))
|
get_user(rseq_kernel_fields(current)->mm_cid, &rseq->mm_cid))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
* Activate the registration by setting the rseq area address, length
|
||||||
|
* and signature in the task struct.
|
||||||
|
*/
|
||||||
|
current->rseq = rseq;
|
||||||
|
current->rseq_len = rseq_len;
|
||||||
|
current->rseq_sig = sig;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If rseq was previously inactive, and has just been
|
* If rseq was previously inactive, and has just been
|
||||||
* registered, ensure the cpu_id_start and cpu_id fields
|
* registered, ensure the cpu_id_start and cpu_id fields
|
||||||
|
|
|
@ -3698,10 +3698,28 @@ static inline int __mm_cid_try_get(struct task_struct *t, struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
struct cpumask *cidmask = mm_cidmask(mm);
|
struct cpumask *cidmask = mm_cidmask(mm);
|
||||||
struct mm_cid __percpu *pcpu_cid = mm->pcpu_cid;
|
struct mm_cid __percpu *pcpu_cid = mm->pcpu_cid;
|
||||||
int cid = __this_cpu_read(pcpu_cid->recent_cid);
|
int cid, max_nr_cid, allowed_max_nr_cid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After shrinking the number of threads or reducing the number
|
||||||
|
* of allowed cpus, reduce the value of max_nr_cid so expansion
|
||||||
|
* of cid allocation will preserve cache locality if the number
|
||||||
|
* of threads or allowed cpus increase again.
|
||||||
|
*/
|
||||||
|
max_nr_cid = atomic_read(&mm->max_nr_cid);
|
||||||
|
while ((allowed_max_nr_cid = min_t(int, READ_ONCE(mm->nr_cpus_allowed),
|
||||||
|
atomic_read(&mm->mm_users))),
|
||||||
|
max_nr_cid > allowed_max_nr_cid) {
|
||||||
|
/* atomic_try_cmpxchg loads previous mm->max_nr_cid into max_nr_cid. */
|
||||||
|
if (atomic_try_cmpxchg(&mm->max_nr_cid, &max_nr_cid, allowed_max_nr_cid)) {
|
||||||
|
max_nr_cid = allowed_max_nr_cid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Try to re-use recent cid. This improves cache locality. */
|
/* Try to re-use recent cid. This improves cache locality. */
|
||||||
if (!mm_cid_is_unset(cid) && !cpumask_test_and_set_cpu(cid, cidmask))
|
cid = __this_cpu_read(pcpu_cid->recent_cid);
|
||||||
|
if (!mm_cid_is_unset(cid) && cid < max_nr_cid &&
|
||||||
|
!cpumask_test_and_set_cpu(cid, cidmask))
|
||||||
return cid;
|
return cid;
|
||||||
/*
|
/*
|
||||||
* Expand cid allocation if the maximum number of concurrency
|
* Expand cid allocation if the maximum number of concurrency
|
||||||
|
@ -3709,8 +3727,9 @@ static inline int __mm_cid_try_get(struct task_struct *t, struct mm_struct *mm)
|
||||||
* and number of threads. Expanding cid allocation as much as
|
* and number of threads. Expanding cid allocation as much as
|
||||||
* possible improves cache locality.
|
* possible improves cache locality.
|
||||||
*/
|
*/
|
||||||
cid = atomic_read(&mm->max_nr_cid);
|
cid = max_nr_cid;
|
||||||
while (cid < READ_ONCE(mm->nr_cpus_allowed) && cid < atomic_read(&mm->mm_users)) {
|
while (cid < READ_ONCE(mm->nr_cpus_allowed) && cid < atomic_read(&mm->mm_users)) {
|
||||||
|
/* atomic_try_cmpxchg loads previous mm->max_nr_cid into cid. */
|
||||||
if (!atomic_try_cmpxchg(&mm->max_nr_cid, &cid, cid + 1))
|
if (!atomic_try_cmpxchg(&mm->max_nr_cid, &cid, cid + 1))
|
||||||
continue;
|
continue;
|
||||||
if (!cpumask_test_and_set_cpu(cid, cidmask))
|
if (!cpumask_test_and_set_cpu(cid, cidmask))
|
||||||
|
|
Loading…
Add table
Reference in a new issue