Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050// 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/debugfs.h>#include <linux/fault-inject.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 <vdso/futex.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, struct futex_private_hash **fph_p);
#ifdef CONFIG_FUTEX_PRIVATE_HASHstatic 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 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 (fph && futex_ref_put(fph)) wake_up_var(fph->mm);}
static struct futex_hash_bucket *__futex_hash_private(union futex_key *key, struct futex_private_hash *fph){ u32 hash;
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, NULL); 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_mm_phash *mmph = &mm->futex.phash; struct futex_private_hash *fph;
WARN_ON_ONCE(mmph->hash_new);
fph = rcu_dereference_protected(mmph->hash, lockdep_is_held(&mmph->lock)); if (fph) { if (!futex_ref_is_dead(fph)) { mmph->hash_new = new; return false; }
futex_rehash_private(fph, new); } new->state = FR_PERCPU; scoped_guard(rcu) { mmph->batches = get_state_synchronize_rcu(); rcu_assign_pointer(mmph->hash, new); } kvfree_rcu(fph, rcu); return true;}
static void futex_pivot_hash(struct mm_struct *mm){ scoped_guard(mutex, &mm->futex.phash.lock) { struct futex_private_hash *fph;
fph = mm->futex.phash.hash_new; if (fph) { mm->futex.phash.hash_new = NULL; __futex_pivot_hash(mm, fph); } }}
struct futex_private_hash *futex_private_hash(struct mm_struct *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.hash); if (!fph) return NULL;
if (futex_private_hash_get(fph)) return fph; } futex_pivot_hash(mm); goto again;}
struct futex_bucket_ref futex_hash(union futex_key *key){again: scoped_guard(rcu) { struct futex_private_hash *fph = NULL; struct futex_hash_bucket *hb;
hb = __futex_hash(key, NULL, &fph);
if (!fph || futex_private_hash_get(fph)) return (struct futex_bucket_ref){ .hb = hb, .fph = fph }; } futex_pivot_hash(key->private.mm); goto again;}
#else /* !CONFIG_FUTEX_PRIVATE_HASH */
struct futex_bucket_ref futex_hash(union futex_key *key){ return (struct futex_bucket_ref){ .hb = __futex_hash(key, NULL, NULL), .fph = 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 = READ_ONCE(vma->vm_policy); 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 * @fph_p: Pointer to a private hash pointer; output for the private hash * used when set. * * 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, struct futex_private_hash **fph_p){ int node = key->both.node; u32 hash;
#ifdef CONFIG_FUTEX_PRIVATE_HASH if (node == FUTEX_NO_NODE && futex_key_is_private(key)) { if (!fph) fph = rcu_dereference(key->private.mm->futex.phash.hash); if (fph && fph->hash_mask) { if (fph_p) *fph_p = fph; return __futex_hash_private(key, fph); } }#endif
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 * 1ns 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 (get_user_inline(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 && put_user_inline(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){ /* * 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); __acquire(q->lock_ptr);}
void futex_q_unlock(struct futex_hash_bucket *hb){ 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, unsigned int mod, bool pending_op){ bool pi = !!(mod & FUTEX_ROBUST_MOD_PI); 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->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 * * 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, NULL, 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, NULL, 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 *mod){ unsigned long uentry;
if (get_user(uentry, (unsigned long __user *)head)) return -EFAULT;
*entry = (void __user *)(uentry & ~FUTEX_ROBUST_MOD_MASK); *mod = uentry & FUTEX_ROBUST_MOD_MASK;
return 0;}
/* * Walk curr->futex.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->futex.robust_list; unsigned int limit = ROBUST_LIST_LIMIT, cur_mod, next_mod, pend_mod; struct robust_list __user *entry, *next_entry, *pending; 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, &cur_mod)) 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, &pend_mod)) 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_mod); /* * 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, cur_mod, HANDLE_DEATH_LIST)) return; } if (rc) return; entry = next_entry; cur_mod = next_mod; /* * Avoid excessively long or circular lists: */ if (!--limit) break;
cond_resched(); }
if (pending) { handle_futex_death((void __user *)pending + futex_offset, curr, pend_mod, HANDLE_DEATH_PENDING); }}
static bool robust_list_clear_pending(unsigned long __user *pop){ struct robust_list_head __user *head = current->futex.robust_list;
if (!put_user(0UL, pop)) return true;
/* * Just give up. The robust list head is usually part of TLS, so the * chance that this gets resolved is close to zero. * * If @pop_addr is the robust_list_head::list_op_pending pointer then * clear the robust list head pointer to prevent further damage when the * task exits. Better a few stale futexes than corrupted memory. But * that's mostly an academic exercise. */ if (pop == (unsigned long __user *)&head->list_op_pending) current->futex.robust_list = NULL; return false;}
#ifdef CONFIG_COMPATstatic 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 intcompat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry, compat_uptr_t __user *head, unsigned int *pflags){ if (get_user(*uentry, head)) return -EFAULT;
*entry = compat_ptr((*uentry) & ~FUTEX_ROBUST_MOD_MASK); *pflags = (unsigned int)(*uentry) & FUTEX_ROBUST_MOD_MASK;
return 0;}
/* * Walk curr->futex.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 = current->futex.compat_robust_list; unsigned int limit = ROBUST_LIST_LIMIT, cur_mod, next_mod, pend_mod; struct robust_list __user *entry, *next_entry, *pending; 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, &cur_mod)) 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, &pend_mod)) 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_mod); /* * 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, cur_mod, HANDLE_DEATH_LIST)) return; } if (rc) return; uentry = next_uentry; entry = next_entry; cur_mod = next_mod; /* * 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, pend_mod, HANDLE_DEATH_PENDING); }}
static bool compat_robust_list_clear_pending(u32 __user *pop){ struct compat_robust_list_head __user *head = current->futex.compat_robust_list;
if (!put_user(0U, pop)) return true;
/* See comment in robust_list_clear_pending(). */ if (pop == &head->list_op_pending) current->futex.compat_robust_list = NULL; return false;}#elsestatic bool compat_robust_list_clear_pending(u32 __user *pop_addr) { return false; }#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->futex.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)(current->mm); /* * 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(hbr, hbr)(&key); auto hb = hbr.hb;
/* * 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);}#elsestatic inline void exit_pi_state_list(struct task_struct *curr) { }#endif
bool futex_robust_list_clear_pending(void __user *pop, unsigned int flags){ bool size32bit = !!(flags & FLAGS_ROBUST_LIST32);
if (!IS_ENABLED(CONFIG_64BIT) && !size32bit) return false;
if (IS_ENABLED(CONFIG_64BIT) && size32bit) return compat_robust_list_clear_pending(pop);
return robust_list_clear_pending(pop);}
#ifdef CONFIG_FUTEX_ROBUST_UNLOCKvoid __futex_fixup_robust_unlock(struct pt_regs *regs, struct futex_unlock_cs_range *csr){ /* * arch_futex_robust_unlock_get_pop() returns the list pending op pointer from * @regs if the try_cmpxchg() succeeded. */ void __user *pop = arch_futex_robust_unlock_get_pop(regs);
if (!pop) return;
futex_robust_list_clear_pending(pop, csr->pop_size32 ? FLAGS_ROBUST_LIST32 : 0);}#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
static void futex_cleanup(struct task_struct *tsk){ if (unlikely(tsk->futex.robust_list)) { exit_robust_list(tsk); tsk->futex.robust_list = NULL; }
#ifdef CONFIG_COMPAT if (unlikely(tsk->futex.compat_robust_list)) { compat_exit_robust_list(tsk); tsk->futex.compat_robust_list = NULL; }#endif
if (unlikely(!list_empty(&tsk->futex.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) { __assume_ctx_lock(&tsk->futex.exit_mutex); mutex_unlock(&tsk->futex.exit_mutex); } tsk->futex.state = FUTEX_STATE_DEAD;}
static void futex_cleanup_begin(struct task_struct *tsk) __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 * 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) __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; /* * 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){ atomic_set(&fhb->waiters, 0); plist_head_init(&fhb->chain); spin_lock_init(&fhb->lock);}
#define FH_CUSTOM 0x01
#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.phash.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.phash.atomic, LONG_MAX); smp_store_release(&fph->state, FR_ATOMIC);
call_rcu_hurry(&mm->futex.phash.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.phash.ref, cpu); count += *ptr; *ptr = 0; }
/* * Re-init for the next cycle. */ this_cpu_inc(*mm->futex.phash.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.phash.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.phash.rcu); struct futex_private_hash *fph = rcu_dereference_raw(mm->futex.phash.hash);
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.hash) != 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.phash.lock); * fph = mm->futex.phash.hash; * rcu_assign_pointer(&mm->futex.phash.hash, 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.phash.batches)) { /* * There was a grace-period, we can begin now. */ __futex_ref_atomic_begin(fph); return; }
call_rcu_hurry(&mm->futex.phash.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.phash.ref); return true; }
return atomic_long_inc_not_zero(&mm->futex.phash.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.phash.ref); return false; }
return atomic_long_dec_and_test(&mm->futex.phash.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.phash.atomic) == 0;}
static void futex_hash_init_mm(struct futex_mm_data *fd){ memset(&fd->phash, 0, sizeof(fd->phash)); mutex_init(&fd->phash.lock); fd->phash.batches = get_state_synchronize_rcu();}
void futex_hash_free(struct mm_struct *mm){ struct futex_private_hash *fph;
free_percpu(mm->futex.phash.ref); kvfree(mm->futex.phash.hash_new); fph = rcu_dereference_raw(mm->futex.phash.hash); if (fph) kvfree(fph);}
static bool futex_pivot_pending(struct mm_struct *mm){ struct futex_private_hash *fph;
guard(rcu)();
if (!mm->futex.phash.hash_new) return true;
fph = rcu_dereference(mm->futex.phash.hash); 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.hash); if (fph && !fph->hash_mask) { if (custom) return -EBUSY; return 0; } }
if (!mm->futex.phash.ref) { /* * This will always be allocated by the first thread and * therefore requires no locking. */ mm->futex.phash.ref = alloc_percpu(unsigned int); if (!mm->futex.phash.ref) return -ENOMEM; this_cpu_inc(*mm->futex.phash.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]);
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.phash.lock) { struct futex_private_hash *free __free(kvfree) = NULL; struct futex_private_hash *cur, *new;
cur = rcu_dereference_protected(mm->futex.phash.hash, lockdep_is_held(&mm->futex.phash.lock)); new = mm->futex.phash.hash_new; mm->futex.phash.hash_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.hash_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_hash 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.hash); 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.hash); if (fph && fph->hash_mask) return fph->hash_mask + 1; return 0;}#else /* CONFIG_FUTEX_PRIVATE_HASH */static inline int futex_hash_allocate(unsigned int hslots, unsigned int flags) { return -EINVAL; }static inline int futex_hash_get_slots(void) { return 0; }static inline void futex_hash_init_mm(struct futex_mm_data *fd) { }#endif /* !CONFIG_FUTEX_PRIVATE_HASH */
#ifdef CONFIG_FUTEX_ROBUST_UNLOCKstatic void futex_invalidate_cs_ranges(struct futex_mm_data *fd){ /* * Invalidate start_ip so that the quick check fails for ip >= start_ip * if VDSO is not mapped or the second slot is not available for compat * tasks as they use VDSO32 which does not provide the 64-bit pointer * variant. */ for (int i = 0; i < FUTEX_ROBUST_MAX_CS_RANGES; i++) fd->unlock.cs_ranges[i].start_ip = ~0UL;}
void futex_reset_cs_ranges(struct futex_mm_data *fd){ memset(fd->unlock.cs_ranges, 0, sizeof(fd->unlock.cs_ranges)); futex_invalidate_cs_ranges(fd);}
static void futex_robust_unlock_init_mm(struct futex_mm_data *fd){ /* mm_dup() preserves the range, mm_alloc() clears it */ if (!fd->unlock.cs_ranges[0].start_ip) futex_invalidate_cs_ranges(fd);}#else /* CONFIG_FUTEX_ROBUST_UNLOCK */static inline void futex_robust_unlock_init_mm(struct futex_mm_data *fd) { }#endif /* !CONFIG_FUTEX_ROBUST_UNLOCK */
#if defined(CONFIG_FUTEX_PRIVATE_HASH) || defined(CONFIG_FUTEX_ROBUST_UNLOCK)void futex_mm_init(struct mm_struct *mm){ futex_hash_init_mm(&mm->futex); futex_robust_unlock_init_mm(&mm->futex);}#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]);
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);