futex: Move futex task related data into a struct
Having all these members in task_struct along with the required #ifdeffery is annoying, does not allow efficient initializing of the data with memset() and makes extending it tedious. Move it into a data structure and fix up all usage sites. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260602090535.308220888@kernel.org
This commit is contained in:
1 parent
c06cd66387
commit
c1ffc9c6e4
8 files changed
+102
-84
No files matched your search
+31
-30
@@ -32,18 +32,19 @@
|
||||
* "But they come in a choice of three flavours!"
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/plist.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/fault-inject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/mempolicy.h>
|
||||
#include <linux/mmap_lock.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/plist.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <linux/rseq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "futex.h"
|
||||
#include "../locking/rtmutex_common.h"
|
||||
@@ -829,7 +830,7 @@ void wait_for_owner_exiting(int ret, struct task_struct *exiting)
|
||||
if (WARN_ON_ONCE(ret == -EBUSY && !exiting))
|
||||
return;
|
||||
|
||||
mutex_lock(&exiting->futex_exit_mutex);
|
||||
mutex_lock(&exiting->futex.exit_mutex);
|
||||
/*
|
||||
* No point in doing state checking here. If the waiter got here
|
||||
* while the task was in exec()->exec_futex_release() then it can
|
||||
@@ -838,7 +839,7 @@ void wait_for_owner_exiting(int ret, struct task_struct *exiting)
|
||||
* already. Highly unlikely and not a problem. Just one more round
|
||||
* through the futex maze.
|
||||
*/
|
||||
mutex_unlock(&exiting->futex_exit_mutex);
|
||||
mutex_unlock(&exiting->futex.exit_mutex);
|
||||
|
||||
put_task_struct(exiting);
|
||||
}
|
||||
@@ -1047,7 +1048,7 @@ retry:
|
||||
*
|
||||
* In both cases the following conditions are met:
|
||||
*
|
||||
* 1) task->robust_list->list_op_pending != NULL
|
||||
* 1) task->futex.robust_list->list_op_pending != NULL
|
||||
* @pending_op == true
|
||||
* 2) The owner part of user space futex value == 0
|
||||
* 3) Regular futex: @pi == false
|
||||
@@ -1152,7 +1153,7 @@ static inline int fetch_robust_entry(struct robust_list __user **entry,
|
||||
*/
|
||||
static void exit_robust_list(struct task_struct *curr)
|
||||
{
|
||||
struct robust_list_head __user *head = curr->robust_list;
|
||||
struct robust_list_head __user *head = curr->futex.robust_list;
|
||||
struct robust_list __user *entry, *next_entry, *pending;
|
||||
unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
|
||||
unsigned int next_pi;
|
||||
@@ -1246,7 +1247,7 @@ compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **ent
|
||||
*/
|
||||
static void compat_exit_robust_list(struct task_struct *curr)
|
||||
{
|
||||
struct compat_robust_list_head __user *head = curr->compat_robust_list;
|
||||
struct compat_robust_list_head __user *head = curr->futex.compat_robust_list;
|
||||
struct robust_list __user *entry, *next_entry, *pending;
|
||||
unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
|
||||
unsigned int next_pi;
|
||||
@@ -1322,7 +1323,7 @@ static void compat_exit_robust_list(struct task_struct *curr)
|
||||
*/
|
||||
static void exit_pi_state_list(struct task_struct *curr)
|
||||
{
|
||||
struct list_head *next, *head = &curr->pi_state_list;
|
||||
struct list_head *next, *head = &curr->futex.pi_state_list;
|
||||
struct futex_pi_state *pi_state;
|
||||
union futex_key key = FUTEX_KEY_INIT;
|
||||
|
||||
@@ -1406,19 +1407,19 @@ static inline void exit_pi_state_list(struct task_struct *curr) { }
|
||||
|
||||
static void futex_cleanup(struct task_struct *tsk)
|
||||
{
|
||||
if (unlikely(tsk->robust_list)) {
|
||||
if (unlikely(tsk->futex.robust_list)) {
|
||||
exit_robust_list(tsk);
|
||||
tsk->robust_list = NULL;
|
||||
tsk->futex.robust_list = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (unlikely(tsk->compat_robust_list)) {
|
||||
if (unlikely(tsk->futex.compat_robust_list)) {
|
||||
compat_exit_robust_list(tsk);
|
||||
tsk->compat_robust_list = NULL;
|
||||
tsk->futex.compat_robust_list = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(!list_empty(&tsk->pi_state_list)))
|
||||
if (unlikely(!list_empty(&tsk->futex.pi_state_list)))
|
||||
exit_pi_state_list(tsk);
|
||||
}
|
||||
|
||||
@@ -1442,23 +1443,23 @@ static void futex_cleanup(struct task_struct *tsk)
|
||||
void futex_exit_recursive(struct task_struct *tsk)
|
||||
{
|
||||
/* If the state is FUTEX_STATE_EXITING then futex_exit_mutex is held */
|
||||
if (tsk->futex_state == FUTEX_STATE_EXITING) {
|
||||
__assume_ctx_lock(&tsk->futex_exit_mutex);
|
||||
mutex_unlock(&tsk->futex_exit_mutex);
|
||||
if (tsk->futex.state == FUTEX_STATE_EXITING) {
|
||||
__assume_ctx_lock(&tsk->futex.exit_mutex);
|
||||
mutex_unlock(&tsk->futex.exit_mutex);
|
||||
}
|
||||
tsk->futex_state = FUTEX_STATE_DEAD;
|
||||
tsk->futex.state = FUTEX_STATE_DEAD;
|
||||
}
|
||||
|
||||
static void futex_cleanup_begin(struct task_struct *tsk)
|
||||
__acquires(&tsk->futex_exit_mutex)
|
||||
__acquires(&tsk->futex.exit_mutex)
|
||||
{
|
||||
/*
|
||||
* Prevent various race issues against a concurrent incoming waiter
|
||||
* including live locks by forcing the waiter to block on
|
||||
* tsk->futex_exit_mutex when it observes FUTEX_STATE_EXITING in
|
||||
* tsk->futex.exit_mutex when it observes FUTEX_STATE_EXITING in
|
||||
* attach_to_pi_owner().
|
||||
*/
|
||||
mutex_lock(&tsk->futex_exit_mutex);
|
||||
mutex_lock(&tsk->futex.exit_mutex);
|
||||
|
||||
/*
|
||||
* Switch the state to FUTEX_STATE_EXITING under tsk->pi_lock.
|
||||
@@ -1472,23 +1473,23 @@ static void futex_cleanup_begin(struct task_struct *tsk)
|
||||
* be observed in exit_pi_state_list().
|
||||
*/
|
||||
raw_spin_lock_irq(&tsk->pi_lock);
|
||||
tsk->futex_state = FUTEX_STATE_EXITING;
|
||||
tsk->futex.state = FUTEX_STATE_EXITING;
|
||||
raw_spin_unlock_irq(&tsk->pi_lock);
|
||||
}
|
||||
|
||||
static void futex_cleanup_end(struct task_struct *tsk, int state)
|
||||
__releases(&tsk->futex_exit_mutex)
|
||||
__releases(&tsk->futex.exit_mutex)
|
||||
{
|
||||
/*
|
||||
* Lockless store. The only side effect is that an observer might
|
||||
* take another loop until it becomes visible.
|
||||
*/
|
||||
tsk->futex_state = state;
|
||||
tsk->futex.state = state;
|
||||
/*
|
||||
* Drop the exit protection. This unblocks waiters which observed
|
||||
* FUTEX_STATE_EXITING to reevaluate the state.
|
||||
*/
|
||||
mutex_unlock(&tsk->futex_exit_mutex);
|
||||
mutex_unlock(&tsk->futex.exit_mutex);
|
||||
}
|
||||
|
||||
void futex_exec_release(struct task_struct *tsk)
|
||||
|
||||
+13
-13
@@ -14,7 +14,7 @@ int refill_pi_state_cache(void)
|
||||
{
|
||||
struct futex_pi_state *pi_state;
|
||||
|
||||
if (likely(current->pi_state_cache))
|
||||
if (likely(current->futex.pi_state_cache))
|
||||
return 0;
|
||||
|
||||
pi_state = kzalloc_obj(*pi_state);
|
||||
@@ -28,17 +28,17 @@ int refill_pi_state_cache(void)
|
||||
refcount_set(&pi_state->refcount, 1);
|
||||
pi_state->key = FUTEX_KEY_INIT;
|
||||
|
||||
current->pi_state_cache = pi_state;
|
||||
current->futex.pi_state_cache = pi_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct futex_pi_state *alloc_pi_state(void)
|
||||
{
|
||||
struct futex_pi_state *pi_state = current->pi_state_cache;
|
||||
struct futex_pi_state *pi_state = current->futex.pi_state_cache;
|
||||
|
||||
WARN_ON(!pi_state);
|
||||
current->pi_state_cache = NULL;
|
||||
current->futex.pi_state_cache = NULL;
|
||||
|
||||
return pi_state;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ static void pi_state_update_owner(struct futex_pi_state *pi_state,
|
||||
if (new_owner) {
|
||||
raw_spin_lock(&new_owner->pi_lock);
|
||||
WARN_ON(!list_empty(&pi_state->list));
|
||||
list_add(&pi_state->list, &new_owner->pi_state_list);
|
||||
list_add(&pi_state->list, &new_owner->futex.pi_state_list);
|
||||
pi_state->owner = new_owner;
|
||||
raw_spin_unlock(&new_owner->pi_lock);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ void put_pi_state(struct futex_pi_state *pi_state)
|
||||
raw_spin_unlock_irqrestore(&pi_state->pi_mutex.wait_lock, flags);
|
||||
}
|
||||
|
||||
if (current->pi_state_cache) {
|
||||
if (current->futex.pi_state_cache) {
|
||||
kfree(pi_state);
|
||||
} else {
|
||||
/*
|
||||
@@ -106,7 +106,7 @@ void put_pi_state(struct futex_pi_state *pi_state)
|
||||
*/
|
||||
pi_state->owner = NULL;
|
||||
refcount_set(&pi_state->refcount, 1);
|
||||
current->pi_state_cache = pi_state;
|
||||
current->futex.pi_state_cache = pi_state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ void put_pi_state(struct futex_pi_state *pi_state)
|
||||
*
|
||||
* p->pi_lock:
|
||||
*
|
||||
* p->pi_state_list -> pi_state->list, relation
|
||||
* p->futex.pi_state_list -> pi_state->list, relation
|
||||
* pi_mutex->owner -> pi_state->owner, relation
|
||||
*
|
||||
* pi_state->refcount:
|
||||
@@ -327,7 +327,7 @@ static int handle_exit_race(u32 __user *uaddr, u32 uval,
|
||||
* If the futex exit state is not yet FUTEX_STATE_DEAD, tell the
|
||||
* caller that the alleged owner is busy.
|
||||
*/
|
||||
if (tsk && tsk->futex_state != FUTEX_STATE_DEAD)
|
||||
if (tsk && tsk->futex.state != FUTEX_STATE_DEAD)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
@@ -346,8 +346,8 @@ static int handle_exit_race(u32 __user *uaddr, u32 uval,
|
||||
* *uaddr = 0xC0000000; tsk = get_task(PID);
|
||||
* } if (!tsk->flags & PF_EXITING) {
|
||||
* ... attach();
|
||||
* tsk->futex_state = } else {
|
||||
* FUTEX_STATE_DEAD; if (tsk->futex_state !=
|
||||
* tsk->futex.state = } else {
|
||||
* FUTEX_STATE_DEAD; if (tsk->futex.state !=
|
||||
* FUTEX_STATE_DEAD)
|
||||
* return -EAGAIN;
|
||||
* return -ESRCH; <--- FAIL
|
||||
@@ -396,7 +396,7 @@ static void __attach_to_pi_owner(struct task_struct *p, union futex_key *key,
|
||||
pi_state->key = *key;
|
||||
|
||||
WARN_ON(!list_empty(&pi_state->list));
|
||||
list_add(&pi_state->list, &p->pi_state_list);
|
||||
list_add(&pi_state->list, &p->futex.pi_state_list);
|
||||
/*
|
||||
* Assignment without holding pi_state->pi_mutex.wait_lock is safe
|
||||
* because there is no concurrency as the object is not published yet.
|
||||
@@ -440,7 +440,7 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
|
||||
* in futex_exit_release(), we do this protected by p->pi_lock:
|
||||
*/
|
||||
raw_spin_lock_irq(&p->pi_lock);
|
||||
if (unlikely(p->futex_state != FUTEX_STATE_OK)) {
|
||||
if (unlikely(p->futex.state != FUTEX_STATE_OK)) {
|
||||
/*
|
||||
* The task is on the way out. When the futex state is
|
||||
* FUTEX_STATE_DEAD, we know that the task has finished
|
||||
|
||||
+8
-15
@@ -25,17 +25,13 @@
|
||||
* @head: pointer to the list-head
|
||||
* @len: length of the list-head, as userspace expects
|
||||
*/
|
||||
SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head,
|
||||
size_t, len)
|
||||
SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head, size_t, len)
|
||||
{
|
||||
/*
|
||||
* The kernel knows only one size for now:
|
||||
*/
|
||||
/* The kernel knows only one size for now. */
|
||||
if (unlikely(len != sizeof(*head)))
|
||||
return -EINVAL;
|
||||
|
||||
current->robust_list = head;
|
||||
|
||||
current->futex.robust_list = head;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,9 +39,9 @@ static inline void __user *futex_task_robust_list(struct task_struct *p, bool co
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (compat)
|
||||
return p->compat_robust_list;
|
||||
return p->futex.compat_robust_list;
|
||||
#endif
|
||||
return p->robust_list;
|
||||
return p->futex.robust_list;
|
||||
}
|
||||
|
||||
static void __user *futex_get_robust_list_common(int pid, bool compat)
|
||||
@@ -475,15 +471,13 @@ SYSCALL_DEFINE4(futex_requeue,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE2(set_robust_list,
|
||||
struct compat_robust_list_head __user *, head,
|
||||
compat_size_t, len)
|
||||
COMPAT_SYSCALL_DEFINE2(set_robust_list, struct compat_robust_list_head __user *, head,
|
||||
compat_size_t, len)
|
||||
{
|
||||
if (unlikely(len != sizeof(*head)))
|
||||
return -EINVAL;
|
||||
|
||||
current->compat_robust_list = head;
|
||||
|
||||
current->futex.compat_robust_list = head;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -523,4 +517,3 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
|
||||
return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);
|
||||
}
|
||||
#endif /* CONFIG_COMPAT_32BIT_TIME */
|
||||
|
||||
Reference in new issue
Block a user