// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Fast Userspace Mutexes ( which I call " Futexes ! " ) .
* ( C ) Rusty Russell , IBM 2002
*
* Generalized futexes , futex requeueing , misc fixes by Ingo Molnar
* ( C ) Copyright 2003 Red Hat Inc , All Rights Reserved
*
* Removed page pinning , fix privately mapped COW pages and other cleanups
* ( C ) Copyright 2003 , 2004 Jamie Lokier
*
* Robust futex support started by Ingo Molnar
* ( C ) Copyright 2006 Red Hat Inc , All Rights Reserved
* Thanks to Thomas Gleixner for suggestions , analysis and fixes .
*
* PI - futex support started by Ingo Molnar and Thomas Gleixner
* Copyright ( C ) 2006 Red Hat , Inc . , Ingo Molnar < mingo @ redhat . com >
* Copyright ( C ) 2006 Timesys Corp . , Thomas Gleixner < tglx @ timesys . com >
*
* PRIVATE futexes by Eric Dumazet
* Copyright ( C ) 2007 Eric Dumazet < dada1 @ cosmosbay . com >
*
* Requeue - PI support by Darren Hart < dvhltc @ us . ibm . com >
* Copyright ( C ) IBM Corporation , 2009
* Thanks to Thomas Gleixner for conceptual design and careful reviews .
*
* Thanks to Ben LaHaise for yelling " hashed waitqueues " loudly
* enough at me , Linus for the original ( flawed ) idea , Matthew
* Kirkwood for proof - of - concept implementation .
*
* " The futexes are also cursed . "
* " 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/mempolicy.h>
#include <linux/mmap_lock.h>
#include "futex.h"
#include "../locking/rtmutex_common.h"
/*
* The base of the bucket array and its size are always used together
* ( after initialization only in futex_hash ( ) ) , so ensure that they
* reside in the same cacheline .
*/
static struct {
unsigned long hashmask;
unsigned int hashshift;
struct futex_hash_bucket *queues[MAX_NUMNODES];
} __futex_data __read_mostly __aligned(2 *sizeof (long ));
#define futex_hashmask (__futex_data.hashmask)
#define futex_hashshift (__futex_data.hashshift)
#define futex_queues (__futex_data.queues)
struct futex_private_hash {
int state;
unsigned int hash_mask;
struct rcu_head rcu;
void *mm;
bool custom;
struct futex_hash_bucket queues[];
};
/*
* Fault injections for futexes .
*/
#ifdef CONFIG_FAIL_FUTEX
static struct {
struct fault_attr attr;
bool ignore_private;
} fail_futex = {
.attr = FAULT_ATTR_INITIALIZER,
.ignore_private = false ,
};
static int __init setup_fail_futex(char *str)
{
return setup_fault_attr(&fail_futex.attr, str);
}
__setup("fail_futex=" , setup_fail_futex);
bool should_fail_futex(bool fshared)
{
if (fail_futex.ignore_private && !fshared)
return false ;
return should_fail(&fail_futex.attr, 1 );
}
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
static int __init fail_futex_debugfs(void )
{
umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
struct dentry *dir;
dir = fault_create_debugfs_attr("fail_futex" , NULL,
&fail_futex.attr);
if (IS_ERR(dir))
return PTR_ERR(dir);
debugfs_create_bool("ignore-private" , mode, dir,
&fail_futex.ignore_private);
return 0 ;
}
late_initcall(fail_futex_debugfs);
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
#endif /* CONFIG_FAIL_FUTEX */
static struct futex_hash_bucket *
__futex_hash(union futex_key *key, struct futex_private_hash *fph);
#ifdef CONFIG_FUTEX_PRIVATE_HASH
static bool futex_ref_get(struct futex_private_hash *fph);
static bool futex_ref_put(struct futex_private_hash *fph);
static bool futex_ref_is_dead(struct futex_private_hash *fph);
enum { FR_PERCPU = 0 , FR_ATOMIC };
static inline bool futex_key_is_private(union futex_key *key)
{
/*
* Relies on get_futex_key ( ) to set either bit for shared
* futexes - - see comment with union futex_key .
*/
return !(key->both.offset & (FUT_OFF_INODE | FUT_OFF_MMSHARED));
}
static bool futex_private_hash_get(struct futex_private_hash *fph)
{
return futex_ref_get(fph);
}
void futex_private_hash_put(struct futex_private_hash *fph)
{
if (futex_ref_put(fph))
wake_up_var(fph->mm);
}
/**
* futex_hash_get - Get an additional reference for the local hash .
* @ hb : ptr to the private local hash .
*
* Obtain an additional reference for the already obtained hash bucket . The
* caller must already own an reference .
*/
void futex_hash_get(struct futex_hash_bucket *hb)
{
struct futex_private_hash *fph = hb->priv;
if (!fph)
return ;
WARN_ON_ONCE(!futex_private_hash_get(fph));
}
void futex_hash_put(struct futex_hash_bucket *hb)
{
struct futex_private_hash *fph = hb->priv;
if (!fph)
return ;
futex_private_hash_put(fph);
}
static struct futex_hash_bucket *
__futex_hash_private(union futex_key *key, struct futex_private_hash *fph)
{
u32 hash;
if (!futex_key_is_private(key))
return NULL;
if (!fph)
fph = rcu_dereference(key->private .mm->futex_phash);
if (!fph || !fph->hash_mask)
return NULL;
hash = jhash2((void *)&key->private .address,
sizeof (key->private .address) / 4 ,
key->both.offset);
return &fph->queues[hash & fph->hash_mask];
}
static void futex_rehash_private(struct futex_private_hash *old,
struct futex_private_hash *new )
{
struct futex_hash_bucket *hb_old, *hb_new;
unsigned int slots = old->hash_mask + 1 ;
unsigned int i;
for (i = 0 ; i < slots; i++) {
struct futex_q *this , *tmp;
hb_old = &old->queues[i];
spin_lock(&hb_old->lock);
plist_for_each_entry_safe(this , tmp, &hb_old->chain, list) {
plist_del(&this ->list, &hb_old->chain);
futex_hb_waiters_dec(hb_old);
WARN_ON_ONCE(this ->lock_ptr != &hb_old->lock);
hb_new = __futex_hash(&this ->key, new );
futex_hb_waiters_inc(hb_new);
/*
* The new pointer isn ' t published yet but an already
* moved user can be unqueued due to timeout or signal .
*/
spin_lock_nested(&hb_new->lock, SINGLE_DEPTH_NESTING);
plist_add(&this ->list, &hb_new->chain);
this ->lock_ptr = &hb_new->lock;
spin_unlock(&hb_new->lock);
}
spin_unlock(&hb_old->lock);
}
}
static bool __futex_pivot_hash(struct mm_struct *mm,
struct futex_private_hash *new )
{
struct futex_private_hash *fph;
WARN_ON_ONCE(mm->futex_phash_new);
fph = rcu_dereference_protected(mm->futex_phash,
lockdep_is_held(&mm->futex_hash_lock));
if (fph) {
if (!futex_ref_is_dead(fph)) {
mm->futex_phash_new = new ;
return false ;
}
futex_rehash_private(fph, new );
}
new ->state = FR_PERCPU;
scoped_guard(rcu) {
mm->futex_batches = get_state_synchronize_rcu();
rcu_assign_pointer(mm->futex_phash, new );
}
kvfree_rcu(fph, rcu);
return true ;
}
static void futex_pivot_hash(struct mm_struct *mm)
{
scoped_guard(mutex, &mm->futex_hash_lock) {
struct futex_private_hash *fph;
fph = mm->futex_phash_new;
if (fph) {
mm->futex_phash_new = NULL;
__futex_pivot_hash(mm, fph);
}
}
}
struct futex_private_hash *futex_private_hash(void )
{
struct mm_struct *mm = current->mm;
/*
* Ideally we don ' t loop . If there is a replacement in progress
* then a new private hash is already prepared and a reference can ' t be
* obtained once the last user dropped it ' s .
* In that case we block on mm_struct : : futex_hash_lock and either have
* to perform the replacement or wait while someone else is doing the
* job . Eitherway , on the second iteration we acquire a reference on the
* new private hash or loop again because a new replacement has been
* requested .
*/
again:
scoped_guard(rcu) {
struct futex_private_hash *fph;
fph = rcu_dereference(mm->futex_phash);
if (!fph)
return NULL;
if (futex_private_hash_get(fph))
return fph;
}
futex_pivot_hash(mm);
goto again;
}
struct futex_hash_bucket *futex_hash(union futex_key *key)
{
struct futex_private_hash *fph;
struct futex_hash_bucket *hb;
again:
scoped_guard(rcu) {
hb = __futex_hash(key, NULL);
fph = hb->priv;
if (!fph || futex_private_hash_get(fph))
return hb;
}
futex_pivot_hash(key->private .mm);
goto again;
}
#else /* !CONFIG_FUTEX_PRIVATE_HASH */
static struct futex_hash_bucket *
__futex_hash_private(union futex_key *key, struct futex_private_hash *fph)
{
return NULL;
}
struct futex_hash_bucket *futex_hash(union futex_key *key)
{
return __futex_hash(key, NULL);
}
#endif /* CONFIG_FUTEX_PRIVATE_HASH */
#ifdef CONFIG_FUTEX_MPOL
static int __futex_key_to_node(struct mm_struct *mm, unsigned long addr)
{
struct vm_area_struct *vma = vma_lookup(mm, addr);
struct mempolicy *mpol;
int node = FUTEX_NO_NODE;
if (!vma)
return FUTEX_NO_NODE;
mpol = vma_policy(vma);
if (!mpol)
return FUTEX_NO_NODE;
switch (mpol->mode) {
case MPOL_PREFERRED:
node = first_node(mpol->nodes);
break ;
case MPOL_PREFERRED_MANY:
case MPOL_BIND:
if (mpol->home_node != NUMA_NO_NODE)
node = mpol->home_node;
break ;
default :
break ;
}
return node;
}
static int futex_key_to_node_opt(struct mm_struct *mm, unsigned long addr)
{
int seq, node;
guard(rcu)();
if (!mmap_lock_speculate_try_begin(mm, &seq))
return -EBUSY;
node = __futex_key_to_node(mm, addr);
if (mmap_lock_speculate_retry(mm, seq))
return -EAGAIN;
return node;
}
static int futex_mpol(struct mm_struct *mm, unsigned long addr)
{
int node;
node = futex_key_to_node_opt(mm, addr);
if (node >= FUTEX_NO_NODE)
return node;
guard(mmap_read_lock)(mm);
return __futex_key_to_node(mm, addr);
}
#else /* !CONFIG_FUTEX_MPOL */
static int futex_mpol(struct mm_struct *mm, unsigned long addr)
{
return FUTEX_NO_NODE;
}
#endif /* CONFIG_FUTEX_MPOL */
/**
* _ _ futex_hash - Return the hash bucket
* @ key : Pointer to the futex key for which the hash is calculated
* @ fph : Pointer to private hash if known
*
* We hash on the keys returned from get_futex_key ( see below ) and return the
* corresponding hash bucket .
* If the FUTEX is PROCESS_PRIVATE then a per - process hash bucket ( from the
* private hash ) is returned if existing . Otherwise a hash bucket from the
* global hash is returned .
*/
static struct futex_hash_bucket *
__futex_hash(union futex_key *key, struct futex_private_hash *fph)
{
int node = key->both.node;
u32 hash;
if (node == FUTEX_NO_NODE) {
struct futex_hash_bucket *hb;
hb = __futex_hash_private(key, fph);
if (hb)
return hb;
}
hash = jhash2((u32 *)key,
offsetof(typeof(*key), both.offset) / sizeof (u32),
key->both.offset);
if (node == FUTEX_NO_NODE) {
/*
* In case of ! FLAGS_NUMA , use some unused hash bits to pick a
* node - - this ensures regular futexes are interleaved across
* the nodes and avoids having to allocate multiple
* hash - tables .
*
* NOTE : this isn ' t perfectly uniform , but it is fast and
* handles sparse node masks .
*/
node = (hash >> futex_hashshift) % nr_node_ids;
if (!node_possible(node)) {
node = find_next_bit_wrap(node_possible_map.bits,
nr_node_ids, node);
}
}
return &futex_queues[node][hash & futex_hashmask];
}
/**
* futex_setup_timer - set up the sleeping hrtimer .
* @ time : ptr to the given timeout value
* @ timeout : the hrtimer_sleeper structure to be set up
* @ flags : futex flags
* @ range_ns : optional range in ns
*
* Return : Initialized hrtimer_sleeper structure or NULL if no timeout
* value given
*/
struct hrtimer_sleeper *
futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout,
int flags, u64 range_ns)
{
if (!time)
return NULL;
hrtimer_setup_sleeper_on_stack(timeout,
(flags & FLAGS_CLOCKRT) ? CLOCK_REALTIME : CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
/*
* If range_ns is 0 , calling hrtimer_set_expires_range_ns ( ) is
* effectively the same as calling hrtimer_set_expires ( ) .
*/
hrtimer_set_expires_range_ns(&timeout->timer, *time, range_ns);
return timeout;
}
/*
* Generate a machine wide unique identifier for this inode .
*
* This relies on u64 not wrapping in the life - time of the machine ; which with
* 1 ns resolution means almost 585 years .
*
* This further relies on the fact that a well formed program will not unmap
* the file while it has a ( shared ) futex waiting on it . This mapping will have
* a file reference which pins the mount and inode .
*
* If for some reason an inode gets evicted and read back in again , it will get
* a new sequence number and will _ NOT_ match , even though it is the exact same
* file .
*
* It is important that futex_match ( ) will never have a false - positive , esp .
* for PI futexes that can mess up the state . The above argues that false - negatives
* are only possible for malformed programs .
*/
static u64 get_inode_sequence_number(struct inode *inode)
{
static atomic64_t i_seq;
u64 old;
/* Does the inode already have a sequence number? */
old = atomic64_read(&inode->i_sequence);
if (likely(old))
return old;
for (;;) {
u64 new = atomic64_inc_return(&i_seq);
if (WARN_ON_ONCE(!new ))
continue ;
old = 0 ;
if (!atomic64_try_cmpxchg_relaxed(&inode->i_sequence, &old, new ))
return old;
return new ;
}
}
/**
* get_futex_key ( ) - Get parameters which are the keys for a futex
* @ uaddr : virtual address of the futex
* @ flags : FLAGS_ *
* @ key : address where result is stored .
* @ rw : mapping needs to be read / write ( values : FUTEX_READ ,
* FUTEX_WRITE )
*
* Return : a negative error code or 0
*
* The key words are stored in @ key on success .
*
* For shared mappings ( when @ fshared ) , the key is :
*
* ( inode - > i_sequence , page offset within mapping , offset_within_page )
*
* [ also see get_inode_sequence_number ( ) ]
*
* For private mappings ( or when ! @ fshared ) , the key is :
*
* ( current - > mm , address , 0 )
*
* This allows ( cross process , where applicable ) identification of the futex
* without keeping the page pinned for the duration of the FUTEX_WAIT .
*
* lock_page ( ) might sleep , the caller should not hold a spinlock .
*/
int get_futex_key(u32 __user *uaddr, unsigned int flags, union futex_key *key,
enum futex_access rw)
{
unsigned long address = (unsigned long )uaddr;
struct mm_struct *mm = current->mm;
struct page *page;
struct folio *folio;
struct address_space *mapping;
int node, err, size, ro = 0 ;
bool node_updated = false ;
bool fshared;
fshared = flags & FLAGS_SHARED;
size = futex_size(flags);
if (flags & FLAGS_NUMA)
size *= 2 ;
/*
* The futex address must be " naturally " aligned .
*/
key->both.offset = address % PAGE_SIZE;
if (unlikely((address % size) != 0 ))
return -EINVAL;
address -= key->both.offset;
if (unlikely(!access_ok(uaddr, size)))
return -EFAULT;
if (unlikely(should_fail_futex(fshared)))
return -EFAULT;
node = FUTEX_NO_NODE;
if (flags & FLAGS_NUMA) {
u32 __user *naddr = (void *)uaddr + size / 2 ;
if (futex_get_value(&node, naddr))
return -EFAULT;
if ((node != FUTEX_NO_NODE) &&
((unsigned int )node >= MAX_NUMNODES || !node_possible(node)))
return -EINVAL;
}
if (node == FUTEX_NO_NODE && (flags & FLAGS_MPOL)) {
node = futex_mpol(mm, address);
node_updated = true ;
}
if (flags & FLAGS_NUMA) {
u32 __user *naddr = (void *)uaddr + size / 2 ;
if (node == FUTEX_NO_NODE) {
node = numa_node_id();
node_updated = true ;
}
if (node_updated && futex_put_value(node, naddr))
return -EFAULT;
}
key->both.node = node;
/*
* PROCESS_PRIVATE futexes are fast .
* As the mm cannot disappear under us and the ' key ' only needs
* virtual address , we dont even have to find the underlying vma .
* Note : We do have to check ' uaddr ' is a valid user address ,
* but access_ok ( ) should be faster than find_vma ( )
*/
if (!fshared) {
/*
* On no - MMU , shared futexes are treated as private , therefore
* we must not include the current process in the key . Since
* there is only one address space , the address is a unique key
* on its own .
*/
if (IS_ENABLED(CONFIG_MMU))
key->private .mm = mm;
else
key->private .mm = NULL;
key->private .address = address;
return 0 ;
}
again:
/* Ignore any VERIFY_READ mapping (futex common case) */
if (unlikely(should_fail_futex(true )))
return -EFAULT;
err = get_user_pages_fast(address, 1 , FOLL_WRITE, &page);
/*
* If write access is not required ( eg . FUTEX_WAIT ) , try
* and get read - only access .
*/
if (err == -EFAULT && rw == FUTEX_READ) {
err = get_user_pages_fast(address, 1 , 0 , &page);
ro = 1 ;
}
if (err < 0 )
return err;
else
err = 0 ;
/*
* The treatment of mapping from this point on is critical . The folio
* lock protects many things but in this context the folio lock
* stabilizes mapping , prevents inode freeing in the shared
* file - backed region case and guards against movement to swap cache .
*
* Strictly speaking the folio lock is not needed in all cases being
* considered here and folio lock forces unnecessarily serialization .
* From this point on , mapping will be re - verified if necessary and
* folio lock will be acquired only if it is unavoidable
*
* Mapping checks require the folio so it is looked up now . For
* anonymous pages , it does not matter if the folio is split
* in the future as the key is based on the address . For
* filesystem - backed pages , the precise page is required as the
* index of the page determines the key .
*/
folio = page_folio(page);
mapping = READ_ONCE(folio->mapping);
/*
* If folio - > mapping is NULL , then it cannot be an anonymous
* page ; but it might be the ZERO_PAGE or in the gate area or
* in a special mapping ( all cases which we are happy to fail ) ;
* or it may have been a good file page when get_user_pages_fast
* found it , but truncated or holepunched or subjected to
* invalidate_complete_page2 before we got the folio lock ( also
* cases which we are happy to fail ) . And we hold a reference ,
* so refcount care in invalidate_inode_page ' s remove_mapping
* prevents drop_caches from setting mapping to NULL beneath us .
*
* The case we do have to guard against is when memory pressure made
* shmem_writepage move it from filecache to swapcache beneath us :
* an unlikely race , but we do need to retry for folio - > mapping .
*/
if (unlikely(!mapping)) {
int shmem_swizzled;
/*
* Folio lock is required to identify which special case above
* applies . If this is really a shmem page then the folio lock
* will prevent unexpected transitions .
*/
folio_lock(folio);
shmem_swizzled = folio_test_swapcache(folio) || folio->mapping;
folio_unlock(folio);
folio_put(folio);
if (shmem_swizzled)
goto again;
return -EFAULT;
}
/*
* Private mappings are handled in a simple way .
*
* If the futex key is stored in anonymous memory , then the associated
* object is the mm which is implicitly pinned by the calling process .
*
* NOTE : When userspace waits on a MAP_SHARED mapping , even if
* it ' s a read - only handle , it ' s expected that futexes attach to
* the object not the particular process .
*/
if (folio_test_anon(folio)) {
/*
* A RO anonymous page will never change and thus doesn ' t make
* sense for futex operations .
*/
if (unlikely(should_fail_futex(true )) || ro) {
err = -EFAULT;
goto out;
}
key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
key->private .mm = mm;
key->private .address = address;
} else {
struct inode *inode;
/*
* The associated futex object in this case is the inode and
* the folio - > mapping must be traversed . Ordinarily this should
* be stabilised under folio lock but it ' s not strictly
* necessary in this case as we just want to pin the inode , not
* update i_pages or anything like that .
*
* The RCU read lock is taken as the inode is finally freed
* under RCU . If the mapping still matches expectations then the
* mapping - > host can be safely accessed as being a valid inode .
*/
rcu_read_lock();
if (READ_ONCE(folio->mapping) != mapping) {
rcu_read_unlock();
folio_put(folio);
goto again;
}
inode = READ_ONCE(mapping->host);
if (!inode) {
rcu_read_unlock();
folio_put(folio);
goto again;
}
key->both.offset |= FUT_OFF_INODE; /* inode-based key */
key->shared.i_seq = get_inode_sequence_number(inode);
key->shared.pgoff = page_pgoff(folio, page);
rcu_read_unlock();
}
out:
folio_put(folio);
return err;
}
/**
* fault_in_user_writeable ( ) - Fault in user address and verify RW access
* @ uaddr : pointer to faulting user space address
*
* Slow path to fixup the fault we just took in the atomic write
* access to @ uaddr .
*
* We have no generic implementation of a non - destructive write to the
* user address . We know that we faulted in the atomic pagefault
* disabled section so we can as well avoid the # PF overhead by
* calling get_user_pages ( ) right away .
*/
int fault_in_user_writeable(u32 __user *uaddr)
{
struct mm_struct *mm = current->mm;
int ret;
mmap_read_lock(mm);
ret = fixup_user_fault(mm, (unsigned long )uaddr,
FAULT_FLAG_WRITE, NULL);
mmap_read_unlock(mm);
return ret < 0 ? ret : 0 ;
}
/**
* futex_top_waiter ( ) - Return the highest priority waiter on a futex
* @ hb : the hash bucket the futex_q ' s reside in
* @ key : the futex key ( to distinguish it from other futex futex_q ' s )
*
* Must be called with the hb lock held .
*/
struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb, union futex_key *key)
{
struct futex_q *this ;
plist_for_each_entry(this , &hb->chain, list) {
if (futex_match(&this ->key, key))
return this ;
}
return NULL;
}
/**
* wait_for_owner_exiting - Block until the owner has exited
* @ ret : owner ' s current futex lock status
* @ exiting : Pointer to the exiting task
*
* Caller must hold a refcount on @ exiting .
*/
void wait_for_owner_exiting(int ret, struct task_struct *exiting)
{
if (ret != -EBUSY) {
WARN_ON_ONCE(exiting);
return ;
}
if (WARN_ON_ONCE(ret == -EBUSY && !exiting))
return ;
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
* have any FUTEX_STATE_ * value when the waiter has acquired the
* mutex . OK , if running , EXITING or DEAD if it reached exit ( )
* already . Highly unlikely and not a problem . Just one more round
* through the futex maze .
*/
mutex_unlock(&exiting->futex_exit_mutex);
put_task_struct(exiting);
}
/**
* _ _ futex_unqueue ( ) - Remove the futex_q from its futex_hash_bucket
* @ q : The futex_q to unqueue
*
* The q - > lock_ptr must not be NULL and must be held by the caller .
*/
void __futex_unqueue(struct futex_q *q)
{
struct futex_hash_bucket *hb;
if (WARN_ON_SMP(!q->lock_ptr) || WARN_ON(plist_node_empty(&q->list)))
return ;
lockdep_assert_held(q->lock_ptr);
hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
plist_del(&q->list, &hb->chain);
futex_hb_waiters_dec(hb);
}
/* The key must be already stored in q->key. */
void futex_q_lock(struct futex_q *q, struct futex_hash_bucket *hb)
__acquires(&hb->lock)
{
/*
* Increment the counter before taking the lock so that
* a potential waker won ' t miss a to - be - slept task that is
* waiting for the spinlock . This is safe as all futex_q_lock ( )
* users end up calling futex_queue ( ) . Similarly , for housekeeping ,
* decrement the counter at futex_q_unlock ( ) when some error has
* occurred and we don ' t end up adding the task to the list .
*/
futex_hb_waiters_inc(hb); /* implies smp_mb(); (A) */
q->lock_ptr = &hb->lock;
spin_lock(&hb->lock);
}
void futex_q_unlock(struct futex_hash_bucket *hb)
__releases(&hb->lock)
{
futex_hb_waiters_dec(hb);
spin_unlock(&hb->lock);
}
void __futex_queue(struct futex_q *q, struct futex_hash_bucket *hb,
struct task_struct *task)
{
int prio;
/*
* The priority used to register this element is
* - either the real thread - priority for the real - time threads
* ( i . e . threads with a priority lower than MAX_RT_PRIO )
* - or MAX_RT_PRIO for non - RT threads .
* Thus , all RT - threads are woken first in priority order , and
* the others are woken last , in FIFO order .
*/
prio = min(current->normal_prio, MAX_RT_PRIO);
plist_node_init(&q->list, prio);
plist_add(&q->list, &hb->chain);
q->task = task;
}
/**
* futex_unqueue ( ) - Remove the futex_q from its futex_hash_bucket
* @ q : The futex_q to unqueue
*
* The q - > lock_ptr must not be held by the caller . A call to futex_unqueue ( ) must
* be paired with exactly one earlier call to futex_queue ( ) .
*
* Return :
* - 1 - if the futex_q was still queued ( and we removed unqueued it ) ;
* - 0 - if the futex_q was already removed by the waking thread
*/
int futex_unqueue(struct futex_q *q)
{
spinlock_t *lock_ptr;
int ret = 0 ;
/* RCU so lock_ptr is not going away during locking. */
guard(rcu)();
/* In the common case we don't take the spinlock, which is nice. */
retry:
/*
* q - > lock_ptr can change between this read and the following spin_lock .
* Use READ_ONCE to forbid the compiler from reloading q - > lock_ptr and
* optimizing lock_ptr out of the logic below .
*/
lock_ptr = READ_ONCE(q->lock_ptr);
if (lock_ptr != NULL) {
spin_lock(lock_ptr);
/*
* q - > lock_ptr can change between reading it and
* spin_lock ( ) , causing us to take the wrong lock . This
* corrects the race condition .
*
* Reasoning goes like this : if we have the wrong lock ,
* q - > lock_ptr must have changed ( maybe several times )
* between reading it and the spin_lock ( ) . It can
* change again after the spin_lock ( ) but only if it was
* already changed before the spin_lock ( ) . It cannot ,
* however , change back to the original value . Therefore
* we can detect whether we acquired the correct lock .
*/
if (unlikely(lock_ptr != q->lock_ptr)) {
spin_unlock(lock_ptr);
goto retry;
}
__futex_unqueue(q);
BUG_ON(q->pi_state);
spin_unlock(lock_ptr);
ret = 1 ;
}
return ret;
}
void futex_q_lockptr_lock(struct futex_q *q)
{
spinlock_t *lock_ptr;
/*
* See futex_unqueue ( ) why lock_ptr can change .
*/
guard(rcu)();
retry:
lock_ptr = READ_ONCE(q->lock_ptr);
spin_lock(lock_ptr);
if (unlikely(lock_ptr != q->lock_ptr)) {
spin_unlock(lock_ptr);
goto retry;
}
}
/*
* PI futexes can not be requeued and must remove themselves from the hash
* bucket . The hash bucket lock ( i . e . lock_ptr ) is held .
*/
void futex_unqueue_pi(struct futex_q *q)
{
/*
* If the lock was not acquired ( due to timeout or signal ) then the
* rt_waiter is removed before futex_q is . If this is observed by
* an unlocker after dropping the rtmutex wait lock and before
* acquiring the hash bucket lock , then the unlocker dequeues the
* futex_q from the hash bucket list to guarantee consistent state
* vs . userspace . Therefore the dequeue here must be conditional .
*/
if (!plist_node_empty(&q->list))
__futex_unqueue(q);
BUG_ON(!q->pi_state);
put_pi_state(q->pi_state);
q->pi_state = NULL;
}
/* Constants for the pending_op argument of handle_futex_death */
#define HANDLE_DEATH_PENDING true
#define HANDLE_DEATH_LIST false
/*
* Process a futex - list entry , check whether it ' s owned by the
* dying task , and do notification if so :
*/
static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
bool pi, bool pending_op)
{
u32 uval, nval, mval;
pid_t owner;
int err;
/* Futex address must be 32bit aligned */
if ((((unsigned long )uaddr) % sizeof (*uaddr)) != 0 )
return -1 ;
retry:
if (get_user(uval, uaddr))
return -1 ;
/*
* Special case for regular ( non PI ) futexes . The unlock path in
* user space has two race scenarios :
*
* 1 . The unlock path releases the user space futex value and
* before it can execute the futex ( ) syscall to wake up
* waiters it is killed .
*
* 2 . A woken up waiter is killed before it can acquire the
* futex in user space .
*
* In the second case , the wake up notification could be generated
* by the unlock path in user space after setting the futex value
* to zero or by the kernel after setting the OWNER_DIED bit below .
*
* In both cases the TID validation below prevents a wakeup of
* potential waiters which can cause these waiters to block
* forever .
*
* In both cases the following conditions are met :
*
* 1 ) task - > robust_list - > list_op_pending ! = NULL
* @ pending_op = = true
* 2 ) The owner part of user space futex value = = 0
* 3 ) Regular futex : @ pi = = false
*
* If these conditions are met , it is safe to attempt waking up a
* potential waiter without touching the user space futex value and
* trying to set the OWNER_DIED bit . If the futex value is zero ,
* the rest of the user space mutex state is consistent , so a woken
* waiter will just take over the uncontended futex . Setting the
* OWNER_DIED bit would create inconsistent state and malfunction
* of the user space owner died handling . Otherwise , the OWNER_DIED
* bit is already set , and the woken waiter is expected to deal with
* this .
*/
owner = uval & FUTEX_TID_MASK;
if (pending_op && !pi && !owner) {
futex_wake(uaddr, FLAGS_SIZE_32 | FLAGS_SHARED, 1 ,
FUTEX_BITSET_MATCH_ANY);
return 0 ;
}
if (owner != task_pid_vnr(curr))
return 0 ;
/*
* Ok , this dying thread is truly holding a futex
* of interest . Set the OWNER_DIED bit atomically
* via cmpxchg , and if the value had FUTEX_WAITERS
* set , wake up a waiter ( if any ) . ( We have to do a
* futex_wake ( ) even if OWNER_DIED is already set -
* to handle the rare but possible case of recursive
* thread - death . ) The rest of the cleanup is done in
* userspace .
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
/*
* We are not holding a lock here , but we want to have
* the pagefault_disable / enable ( ) protection because
* we want to handle the fault gracefully . If the
* access fails we try to fault in the futex with R / W
* verification via get_user_pages . get_user ( ) above
* does not guarantee R / W access . If that fails we
* give up and leave the futex locked .
*/
if ((err = futex_cmpxchg_value_locked(&nval, uaddr, uval, mval))) {
switch (err) {
case -EFAULT:
if (fault_in_user_writeable(uaddr))
return -1 ;
goto retry;
case -EAGAIN:
cond_resched();
goto retry;
default :
WARN_ON_ONCE(1 );
return err;
}
}
if (nval != uval)
goto retry;
/*
* Wake robust non - PI futexes here . The wakeup of
* PI futexes happens in exit_pi_state ( ) :
*/
if (!pi && (uval & FUTEX_WAITERS)) {
futex_wake(uaddr, FLAGS_SIZE_32 | FLAGS_SHARED, 1 ,
FUTEX_BITSET_MATCH_ANY);
}
return 0 ;
}
/*
* Fetch a robust - list pointer . Bit 0 signals PI futexes :
*/
static inline int fetch_robust_entry(struct robust_list __user **entry,
struct robust_list __user * __user *head,
unsigned int *pi)
{
unsigned long uentry;
if (get_user(uentry, (unsigned long __user *)head))
return -EFAULT;
*entry = (void __user *)(uentry & ~1 UL);
*pi = uentry & 1 ;
return 0 ;
}
/*
* Walk curr - > robust_list ( very carefully , it ' s a userspace list ! )
* and mark any locks found there dead , and notify any waiters .
*
* We silently return on any sign of list - walking problem .
*/
static void exit_robust_list(struct task_struct *curr)
{
struct robust_list_head __user *head = curr->robust_list;
struct robust_list __user *entry, *next_entry, *pending;
unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
unsigned int next_pi;
unsigned long futex_offset;
int rc;
/*
* Fetch the list head ( which was registered earlier , via
* sys_set_robust_list ( ) ) :
*/
if (fetch_robust_entry(&entry, &head->list.next, &pi))
return ;
/*
* Fetch the relative futex offset :
*/
if (get_user(futex_offset, &head->futex_offset))
return ;
/*
* Fetch any possibly pending lock - add first , and handle it
* if it exists :
*/
if (fetch_robust_entry(&pending, &head->list_op_pending, &pip))
return ;
next_entry = NULL; /* avoid warning with gcc */
while (entry != &head->list) {
/*
* Fetch the next entry in the list before calling
* handle_futex_death :
*/
rc = fetch_robust_entry(&next_entry, &entry->next, &next_pi);
/*
* A pending lock might already be on the list , so
* don ' t process it twice :
*/
if (entry != pending) {
if (handle_futex_death((void __user *)entry + futex_offset,
curr, pi, HANDLE_DEATH_LIST))
return ;
}
if (rc)
return ;
entry = next_entry;
pi = next_pi;
/*
* Avoid excessively long or circular lists :
*/
if (!--limit)
break ;
cond_resched();
}
if (pending) {
handle_futex_death((void __user *)pending + futex_offset,
curr, pip, HANDLE_DEATH_PENDING);
}
}
#ifdef CONFIG_COMPAT
static void __user *futex_uaddr(struct robust_list __user *entry,
compat_long_t futex_offset)
{
compat_uptr_t base = ptr_to_compat(entry);
void __user *uaddr = compat_ptr(base + futex_offset);
return uaddr;
}
/*
* Fetch a robust - list pointer . Bit 0 signals PI futexes :
*/
static inline int
compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
compat_uptr_t __user *head, unsigned int *pi)
{
if (get_user(*uentry, head))
return -EFAULT;
*entry = compat_ptr((*uentry) & ~1 );
*pi = (unsigned int )(*uentry) & 1 ;
return 0 ;
}
/*
* Walk curr - > robust_list ( very carefully , it ' s a userspace list ! )
* and mark any locks found there dead , and notify any waiters .
*
* We silently return on any sign of list - walking problem .
*/
static void compat_exit_robust_list(struct task_struct *curr)
{
struct compat_robust_list_head __user *head = curr->compat_robust_list;
struct robust_list __user *entry, *next_entry, *pending;
unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
unsigned int next_pi;
compat_uptr_t uentry, next_uentry, upending;
compat_long_t futex_offset;
int rc;
/*
* Fetch the list head ( which was registered earlier , via
* sys_set_robust_list ( ) ) :
*/
if (compat_fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))
return ;
/*
* Fetch the relative futex offset :
*/
if (get_user(futex_offset, &head->futex_offset))
return ;
/*
* Fetch any possibly pending lock - add first , and handle it
* if it exists :
*/
if (compat_fetch_robust_entry(&upending, &pending,
&head->list_op_pending, &pip))
return ;
next_entry = NULL; /* avoid warning with gcc */
while (entry != (struct robust_list __user *) &head->list) {
/*
* Fetch the next entry in the list before calling
* handle_futex_death :
*/
rc = compat_fetch_robust_entry(&next_uentry, &next_entry,
(compat_uptr_t __user *)&entry->next, &next_pi);
/*
* A pending lock might already be on the list , so
* dont process it twice :
*/
if (entry != pending) {
void __user *uaddr = futex_uaddr(entry, futex_offset);
if (handle_futex_death(uaddr, curr, pi,
HANDLE_DEATH_LIST))
return ;
}
if (rc)
return ;
uentry = next_uentry;
entry = next_entry;
pi = next_pi;
/*
* Avoid excessively long or circular lists :
*/
if (!--limit)
break ;
cond_resched();
}
if (pending) {
void __user *uaddr = futex_uaddr(pending, futex_offset);
handle_futex_death(uaddr, curr, pip, HANDLE_DEATH_PENDING);
}
}
#endif
#ifdef CONFIG_FUTEX_PI
/*
* This task is holding PI mutexes at exit time = > bad .
* Kernel cleans up PI - state , but userspace is likely hosed .
* ( Robust - futex cleanup is separate and might save the day for userspace . )
*/
static void exit_pi_state_list(struct task_struct *curr)
{
struct list_head *next, *head = &curr->pi_state_list;
struct futex_pi_state *pi_state;
union futex_key key = FUTEX_KEY_INIT;
/*
* The mutex mm_struct : : futex_hash_lock might be acquired .
*/
might_sleep();
/*
* Ensure the hash remains stable ( no resize ) during the while loop
* below . The hb pointer is acquired under the pi_lock so we can ' t block
* on the mutex .
*/
WARN_ON(curr != current);
guard(private_hash)();
/*
* We are a ZOMBIE and nobody can enqueue itself on
* pi_state_list anymore , but we have to be careful
* versus waiters unqueueing themselves :
*/
raw_spin_lock_irq(&curr->pi_lock);
while (!list_empty(head)) {
next = head->next;
pi_state = list_entry(next, struct futex_pi_state, list);
key = pi_state->key;
if (1 ) {
CLASS (hb, hb)(&key);
/*
* We can race against put_pi_state ( ) removing itself from the
* list ( a waiter going away ) . put_pi_state ( ) will first
* decrement the reference count and then modify the list , so
* its possible to see the list entry but fail this reference
* acquire .
*
* In that case ; drop the locks to let put_pi_state ( ) make
* progress and retry the loop .
*/
if (!refcount_inc_not_zero(&pi_state->refcount)) {
raw_spin_unlock_irq(&curr->pi_lock);
cpu_relax();
raw_spin_lock_irq(&curr->pi_lock);
continue ;
}
raw_spin_unlock_irq(&curr->pi_lock);
spin_lock(&hb->lock);
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
raw_spin_lock(&curr->pi_lock);
/*
* We dropped the pi - lock , so re - check whether this
* task still owns the PI - state :
*/
if (head->next != next) {
/* retain curr->pi_lock for the loop invariant */
raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
spin_unlock(&hb->lock);
put_pi_state(pi_state);
continue ;
}
WARN_ON(pi_state->owner != curr);
WARN_ON(list_empty(&pi_state->list));
list_del_init(&pi_state->list);
pi_state->owner = NULL;
raw_spin_unlock(&curr->pi_lock);
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
spin_unlock(&hb->lock);
}
rt_mutex_futex_unlock(&pi_state->pi_mutex);
put_pi_state(pi_state);
raw_spin_lock_irq(&curr->pi_lock);
}
raw_spin_unlock_irq(&curr->pi_lock);
}
#else
static inline void exit_pi_state_list(struct task_struct *curr) { }
#endif
static void futex_cleanup(struct task_struct *tsk)
{
if (unlikely(tsk->robust_list)) {
exit_robust_list(tsk);
tsk->robust_list = NULL;
}
#ifdef CONFIG_COMPAT
if (unlikely(tsk->compat_robust_list)) {
compat_exit_robust_list(tsk);
tsk->compat_robust_list = NULL;
}
#endif
if (unlikely(!list_empty(&tsk->pi_state_list)))
exit_pi_state_list(tsk);
}
/**
* futex_exit_recursive - Set the tasks futex state to FUTEX_STATE_DEAD
* @ tsk : task to set the state on
*
* Set the futex exit state of the task lockless . The futex waiter code
* observes that state when a task is exiting and loops until the task has
* actually finished the futex cleanup . The worst case for this is that the
* waiter runs through the wait loop until the state becomes visible .
*
* This is called from the recursive fault handling path in make_task_dead ( ) .
*
* This is best effort . Either the futex exit code has run already or
* not . If the OWNER_DIED bit has been set on the futex then the waiter can
* take it over . If not , the problem is pushed back to user space . If the
* futex exit code did not run yet , then an already queued waiter might
* block forever , but there is nothing which can be done about that .
*/
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)
mutex_unlock(&tsk->futex_exit_mutex);
tsk->futex_state = FUTEX_STATE_DEAD;
}
static void futex_cleanup_begin(struct task_struct *tsk)
{
/*
* 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
* attach_to_pi_owner ( ) .
*/
mutex_lock(&tsk->futex_exit_mutex);
/*
* Switch the state to FUTEX_STATE_EXITING under tsk - > pi_lock .
*
* This ensures that all subsequent checks of tsk - > futex_state in
* attach_to_pi_owner ( ) must observe FUTEX_STATE_EXITING with
* tsk - > pi_lock held .
*
* It guarantees also that a pi_state which was queued right before
* the state change under tsk - > pi_lock by a concurrent waiter must
* be observed in exit_pi_state_list ( ) .
*/
raw_spin_lock_irq(&tsk->pi_lock);
tsk->futex_state = FUTEX_STATE_EXITING;
raw_spin_unlock_irq(&tsk->pi_lock);
}
static void futex_cleanup_end(struct task_struct *tsk, int state)
{
/*
* Lockless store . The only side effect is that an observer might
* take another loop until it becomes visible .
*/
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);
}
void futex_exec_release(struct task_struct *tsk)
{
/*
* The state handling is done for consistency , but in the case of
* exec ( ) there is no way to prevent further damage as the PID stays
* the same . But for the unlikely and arguably buggy case that a
* futex is held on exec ( ) , this provides at least as much state
* consistency protection which is possible .
*/
futex_cleanup_begin(tsk);
futex_cleanup(tsk);
/*
* Reset the state to FUTEX_STATE_OK . The task is alive and about
* exec a new binary .
*/
futex_cleanup_end(tsk, FUTEX_STATE_OK);
}
void futex_exit_release(struct task_struct *tsk)
{
futex_cleanup_begin(tsk);
futex_cleanup(tsk);
futex_cleanup_end(tsk, FUTEX_STATE_DEAD);
}
static void futex_hash_bucket_init(struct futex_hash_bucket *fhb,
struct futex_private_hash *fph)
{
#ifdef CONFIG_FUTEX_PRIVATE_HASH
fhb->priv = fph;
#endif
atomic_set(&fhb->waiters, 0 );
plist_head_init(&fhb->chain);
spin_lock_init(&fhb->lock);
}
#define FH_CUSTOM 0 x01
#ifdef CONFIG_FUTEX_PRIVATE_HASH
/*
* futex - ref
*
* Heavily inspired by percpu - rwsem / percpu - refcount ; not reusing any of that
* code because it just doesn ' t fit right .
*
* Dual counter , per - cpu / atomic approach like percpu - refcount , except it
* re - initializes the state automatically , such that the fph swizzle is also a
* transition back to per - cpu .
*/
static void futex_ref_rcu(struct rcu_head *head);
static void __futex_ref_atomic_begin(struct futex_private_hash *fph)
{
struct mm_struct *mm = fph->mm;
/*
* The counter we ' re about to switch to must have fully switched ;
* otherwise it would be impossible for it to have reported success
* from futex_ref_is_dead ( ) .
*/
WARN_ON_ONCE(atomic_long_read(&mm->futex_atomic) != 0 );
/*
* Set the atomic to the bias value such that futex_ref_ { get , put } ( )
* will never observe 0 . Will be fixed up in _ _ futex_ref_atomic_end ( )
* when folding in the percpu count .
*/
atomic_long_set(&mm->futex_atomic, LONG_MAX);
smp_store_release(&fph->state, FR_ATOMIC);
call_rcu_hurry(&mm->futex_rcu, futex_ref_rcu);
}
static void __futex_ref_atomic_end(struct futex_private_hash *fph)
{
struct mm_struct *mm = fph->mm;
unsigned int count = 0 ;
long ret;
int cpu;
/*
* Per _ _ futex_ref_atomic_begin ( ) the state of the fph must be ATOMIC
* and per this RCU callback , everybody must now observe this state and
* use the atomic variable .
*/
WARN_ON_ONCE(fph->state != FR_ATOMIC);
/*
* Therefore the per - cpu counter is now stable , sum and reset .
*/
for_each_possible_cpu(cpu) {
unsigned int *ptr = per_cpu_ptr(mm->futex_ref, cpu);
count += *ptr;
*ptr = 0 ;
}
/*
* Re - init for the next cycle .
*/
this_cpu_inc(*mm->futex_ref); /* 0 -> 1 */
/*
* Add actual count , subtract bias and initial refcount .
*
* The moment this atomic operation happens , futex_ref_is_dead ( ) can
* become true .
*/
ret = atomic_long_add_return(count - LONG_MAX - 1 , &mm->futex_atomic);
if (!ret)
wake_up_var(mm);
WARN_ON_ONCE(ret < 0 );
mmput_async(mm);
}
static void futex_ref_rcu(struct rcu_head *head)
{
struct mm_struct *mm = container_of(head, struct mm_struct, futex_rcu);
struct futex_private_hash *fph = rcu_dereference_raw(mm->futex_phash);
if (fph->state == FR_PERCPU) {
/*
* Per this extra grace - period , everybody must now observe
* fph as the current fph and no previously observed fph ' s
* are in - flight .
*
* Notably , nobody will now rely on the atomic
* futex_ref_is_dead ( ) state anymore so we can begin the
* migration of the per - cpu counter into the atomic .
*/
__futex_ref_atomic_begin(fph);
return ;
}
__futex_ref_atomic_end(fph);
}
/*
* Drop the initial refcount and transition to atomics .
*/
static void futex_ref_drop(struct futex_private_hash *fph)
{
struct mm_struct *mm = fph->mm;
/*
* Can only transition the current fph ;
*/
WARN_ON_ONCE(rcu_dereference_raw(mm->futex_phash) != fph);
/*
* We enqueue at least one RCU callback . Ensure mm stays if the task
* exits before the transition is completed .
*/
mmget(mm);
/*
* In order to avoid the following scenario :
*
* futex_hash ( ) _ _ futex_pivot_hash ( )
* guard ( rcu ) ; guard ( mm - > futex_hash_lock ) ;
* fph = mm - > futex_phash ;
* rcu_assign_pointer ( & mm - > futex_phash , new ) ;
* futex_hash_allocate ( )
* futex_ref_drop ( )
* fph - > state = FR_ATOMIC ;
* atomic_set ( , BIAS ) ;
*
* futex_private_hash_get ( fph ) ; // OOPS
*
* Where an old fph ( which is FR_ATOMIC ) and should fail on
* inc_not_zero , will succeed because a new transition is started and
* the atomic is bias ' ed away from 0 .
*
* There must be at least one full grace - period between publishing a
* new fph and trying to replace it .
*/
if (poll_state_synchronize_rcu(mm->futex_batches)) {
/*
* There was a grace - period , we can begin now .
*/
__futex_ref_atomic_begin(fph);
return ;
}
call_rcu_hurry(&mm->futex_rcu, futex_ref_rcu);
}
static bool futex_ref_get(struct futex_private_hash *fph)
{
struct mm_struct *mm = fph->mm;
guard(preempt)();
if (READ_ONCE(fph->state) == FR_PERCPU) {
__this_cpu_inc(*mm->futex_ref);
return true ;
}
return atomic_long_inc_not_zero(&mm->futex_atomic);
}
static bool futex_ref_put(struct futex_private_hash *fph)
{
struct mm_struct *mm = fph->mm;
guard(preempt)();
if (READ_ONCE(fph->state) == FR_PERCPU) {
__this_cpu_dec(*mm->futex_ref);
return false ;
}
return atomic_long_dec_and_test(&mm->futex_atomic);
}
static bool futex_ref_is_dead(struct futex_private_hash *fph)
{
struct mm_struct *mm = fph->mm;
guard(rcu)();
if (smp_load_acquire(&fph->state) == FR_PERCPU)
return false ;
return atomic_long_read(&mm->futex_atomic) == 0 ;
}
int futex_mm_init(struct mm_struct *mm)
{
mutex_init(&mm->futex_hash_lock);
RCU_INIT_POINTER(mm->futex_phash, NULL);
mm->futex_phash_new = NULL;
/* futex-ref */
mm->futex_ref = NULL;
atomic_long_set(&mm->futex_atomic, 0 );
mm->futex_batches = get_state_synchronize_rcu();
return 0 ;
}
void futex_hash_free(struct mm_struct *mm)
{
struct futex_private_hash *fph;
free_percpu(mm->futex_ref);
kvfree(mm->futex_phash_new);
fph = rcu_dereference_raw(mm->futex_phash);
if (fph)
kvfree(fph);
}
static bool futex_pivot_pending(struct mm_struct *mm)
{
struct futex_private_hash *fph;
guard(rcu)();
if (!mm->futex_phash_new)
return true ;
fph = rcu_dereference(mm->futex_phash);
return futex_ref_is_dead(fph);
}
static bool futex_hash_less(struct futex_private_hash *a,
struct futex_private_hash *b)
{
/* user provided always wins */
if (!a->custom && b->custom)
return true ;
if (a->custom && !b->custom)
return false ;
/* zero-sized hash wins */
if (!b->hash_mask)
return true ;
if (!a->hash_mask)
return false ;
/* keep the biggest */
if (a->hash_mask < b->hash_mask)
return true ;
if (a->hash_mask > b->hash_mask)
return false ;
return false ; /* equal */
}
static int futex_hash_allocate(unsigned int hash_slots, unsigned int flags)
{
struct mm_struct *mm = current->mm;
struct futex_private_hash *fph;
bool custom = flags & FH_CUSTOM;
int i;
if (hash_slots && (hash_slots == 1 || !is_power_of_2(hash_slots)))
return -EINVAL;
/*
* Once we ' ve disabled the global hash there is no way back .
*/
scoped_guard(rcu) {
fph = rcu_dereference(mm->futex_phash);
if (fph && !fph->hash_mask) {
if (custom)
return -EBUSY;
return 0 ;
}
}
if (!mm->futex_ref) {
/*
* This will always be allocated by the first thread and
* therefore requires no locking .
*/
mm->futex_ref = alloc_percpu(unsigned int );
if (!mm->futex_ref)
return -ENOMEM;
this_cpu_inc(*mm->futex_ref); /* 0 -> 1 */
}
fph = kvzalloc(struct_size(fph, queues, hash_slots),
GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
if (!fph)
return -ENOMEM;
fph->hash_mask = hash_slots ? hash_slots - 1 : 0 ;
fph->custom = custom;
fph->mm = mm;
for (i = 0 ; i < hash_slots; i++)
futex_hash_bucket_init(&fph->queues[i], fph);
if (custom) {
/*
* Only let prctl ( ) wait / retry ; don ' t unduly delay clone ( ) .
*/
again:
wait_var_event(mm, futex_pivot_pending(mm));
}
scoped_guard(mutex, &mm->futex_hash_lock) {
struct futex_private_hash *free __free(kvfree) = NULL;
struct futex_private_hash *cur, *new ;
cur = rcu_dereference_protected(mm->futex_phash,
lockdep_is_held(&mm->futex_hash_lock));
new = mm->futex_phash_new;
mm->futex_phash_new = NULL;
if (fph) {
if (cur && !cur->hash_mask) {
/*
* If two threads simultaneously request the global
* hash then the first one performs the switch ,
* the second one returns here .
*/
free = fph;
mm->futex_phash_new = new ;
return -EBUSY;
}
if (cur && !new ) {
/*
* If we have an existing hash , but do not yet have
* allocated a replacement hash , drop the initial
* reference on the existing hash .
*/
futex_ref_drop(cur);
}
if (new ) {
/*
* Two updates raced ; throw out the lesser one .
*/
if (futex_hash_less(new , fph)) {
free = new ;
new = fph;
} else {
free = fph;
}
} else {
new = fph;
}
fph = NULL;
}
if (new ) {
/*
* Will set mm - > futex_phash_new on failure ;
* futex_private_hash_get ( ) will try again .
*/
if (!__futex_pivot_hash(mm, new ) && custom)
goto again;
}
}
return 0 ;
}
int futex_hash_allocate_default(void )
{
unsigned int threads, buckets, current_buckets = 0 ;
struct futex_private_hash *fph;
if (!current->mm)
return 0 ;
scoped_guard(rcu) {
threads = min_t(unsigned int ,
get_nr_threads(current),
num_online_cpus());
fph = rcu_dereference(current->mm->futex_phash);
if (fph) {
if (fph->custom)
return 0 ;
current_buckets = fph->hash_mask + 1 ;
}
}
/*
* The default allocation will remain within
* 16 < = threads * 4 < = global hash size
*/
buckets = roundup_pow_of_two(4 * threads);
buckets = clamp(buckets, 16 , futex_hashmask + 1 );
if (current_buckets >= buckets)
return 0 ;
return futex_hash_allocate(buckets, 0 );
}
static int futex_hash_get_slots(void )
{
struct futex_private_hash *fph;
guard(rcu)();
fph = rcu_dereference(current->mm->futex_phash);
if (fph && fph->hash_mask)
return fph->hash_mask + 1 ;
return 0 ;
}
#else
static int futex_hash_allocate(unsigned int hash_slots, unsigned int flags)
{
return -EINVAL;
}
static int futex_hash_get_slots(void )
{
return 0 ;
}
#endif
int futex_hash_prctl(unsigned long arg2, unsigned long arg3, unsigned long arg4)
{
unsigned int flags = FH_CUSTOM;
int ret;
switch (arg2) {
case PR_FUTEX_HASH_SET_SLOTS:
if (arg4)
return -EINVAL;
ret = futex_hash_allocate(arg3, flags);
break ;
case PR_FUTEX_HASH_GET_SLOTS:
ret = futex_hash_get_slots();
break ;
default :
ret = -EINVAL;
break ;
}
return ret;
}
static int __init futex_init(void )
{
unsigned long hashsize, i;
unsigned int order, n;
unsigned long size;
#ifdef CONFIG_BASE_SMALL
hashsize = 16 ;
#else
hashsize = 256 * num_possible_cpus();
hashsize /= num_possible_nodes();
hashsize = max(4 , hashsize);
hashsize = roundup_pow_of_two(hashsize);
#endif
futex_hashshift = ilog2(hashsize);
size = sizeof (struct futex_hash_bucket) * hashsize;
order = get_order(size);
for_each_node(n) {
struct futex_hash_bucket *table;
if (order > MAX_PAGE_ORDER)
table = vmalloc_huge_node(size, GFP_KERNEL, n);
else
table = alloc_pages_exact_nid(n, size, GFP_KERNEL);
BUG_ON(!table);
for (i = 0 ; i < hashsize; i++)
futex_hash_bucket_init(&table[i], NULL);
futex_queues[n] = table;
}
futex_hashmask = hashsize - 1 ;
pr_info("futex hash table entries: %lu (%lu bytes on %d NUMA nodes, total %lu KiB, %s).\n" ,
hashsize, size, num_possible_nodes(), size * num_possible_nodes() / 1024 ,
order > MAX_PAGE_ORDER ? "vmalloc" : "linear" );
return 0 ;
}
core_initcall(futex_init);
Messung V0.5 in Prozent C=95 H=96 G=95
¤ Dauer der Verarbeitung: 0.61 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland