xref: /linux-6.15/include/linux/xarray.h (revision 02c02bf1)
1f6bb2a2cSMatthew Wilcox /* SPDX-License-Identifier: GPL-2.0+ */
2f6bb2a2cSMatthew Wilcox #ifndef _LINUX_XARRAY_H
3f6bb2a2cSMatthew Wilcox #define _LINUX_XARRAY_H
4f6bb2a2cSMatthew Wilcox /*
5f6bb2a2cSMatthew Wilcox  * eXtensible Arrays
6f6bb2a2cSMatthew Wilcox  * Copyright (c) 2017 Microsoft Corporation
73d0186bbSMatthew Wilcox  * Author: Matthew Wilcox <[email protected]>
83159f943SMatthew Wilcox  *
93159f943SMatthew Wilcox  * See Documentation/core-api/xarray.rst for how to use the XArray.
10f6bb2a2cSMatthew Wilcox  */
11f6bb2a2cSMatthew Wilcox 
123159f943SMatthew Wilcox #include <linux/bug.h>
13f6bb2a2cSMatthew Wilcox #include <linux/spinlock.h>
143159f943SMatthew Wilcox #include <linux/types.h>
153159f943SMatthew Wilcox 
163159f943SMatthew Wilcox /*
173159f943SMatthew Wilcox  * The bottom two bits of the entry determine how the XArray interprets
183159f943SMatthew Wilcox  * the contents:
193159f943SMatthew Wilcox  *
203159f943SMatthew Wilcox  * 00: Pointer entry
213159f943SMatthew Wilcox  * 10: Internal entry
223159f943SMatthew Wilcox  * x1: Value entry or tagged pointer
233159f943SMatthew Wilcox  *
243159f943SMatthew Wilcox  * Attempting to store internal entries in the XArray is a bug.
25*02c02bf1SMatthew Wilcox  *
26*02c02bf1SMatthew Wilcox  * Most internal entries are pointers to the next node in the tree.
27*02c02bf1SMatthew Wilcox  * The following internal entries have a special meaning:
28*02c02bf1SMatthew Wilcox  *
29*02c02bf1SMatthew Wilcox  * 0-62: Sibling entries
30*02c02bf1SMatthew Wilcox  * 256: Retry entry
313159f943SMatthew Wilcox  */
323159f943SMatthew Wilcox 
333159f943SMatthew Wilcox #define BITS_PER_XA_VALUE	(BITS_PER_LONG - 1)
343159f943SMatthew Wilcox 
353159f943SMatthew Wilcox /**
363159f943SMatthew Wilcox  * xa_mk_value() - Create an XArray entry from an integer.
373159f943SMatthew Wilcox  * @v: Value to store in XArray.
383159f943SMatthew Wilcox  *
393159f943SMatthew Wilcox  * Context: Any context.
403159f943SMatthew Wilcox  * Return: An entry suitable for storing in the XArray.
413159f943SMatthew Wilcox  */
423159f943SMatthew Wilcox static inline void *xa_mk_value(unsigned long v)
433159f943SMatthew Wilcox {
443159f943SMatthew Wilcox 	WARN_ON((long)v < 0);
453159f943SMatthew Wilcox 	return (void *)((v << 1) | 1);
463159f943SMatthew Wilcox }
473159f943SMatthew Wilcox 
483159f943SMatthew Wilcox /**
493159f943SMatthew Wilcox  * xa_to_value() - Get value stored in an XArray entry.
503159f943SMatthew Wilcox  * @entry: XArray entry.
513159f943SMatthew Wilcox  *
523159f943SMatthew Wilcox  * Context: Any context.
533159f943SMatthew Wilcox  * Return: The value stored in the XArray entry.
543159f943SMatthew Wilcox  */
553159f943SMatthew Wilcox static inline unsigned long xa_to_value(const void *entry)
563159f943SMatthew Wilcox {
573159f943SMatthew Wilcox 	return (unsigned long)entry >> 1;
583159f943SMatthew Wilcox }
593159f943SMatthew Wilcox 
603159f943SMatthew Wilcox /**
613159f943SMatthew Wilcox  * xa_is_value() - Determine if an entry is a value.
623159f943SMatthew Wilcox  * @entry: XArray entry.
633159f943SMatthew Wilcox  *
643159f943SMatthew Wilcox  * Context: Any context.
653159f943SMatthew Wilcox  * Return: True if the entry is a value, false if it is a pointer.
663159f943SMatthew Wilcox  */
673159f943SMatthew Wilcox static inline bool xa_is_value(const void *entry)
683159f943SMatthew Wilcox {
693159f943SMatthew Wilcox 	return (unsigned long)entry & 1;
703159f943SMatthew Wilcox }
713159f943SMatthew Wilcox 
723159f943SMatthew Wilcox /**
733159f943SMatthew Wilcox  * xa_tag_pointer() - Create an XArray entry for a tagged pointer.
743159f943SMatthew Wilcox  * @p: Plain pointer.
753159f943SMatthew Wilcox  * @tag: Tag value (0, 1 or 3).
763159f943SMatthew Wilcox  *
773159f943SMatthew Wilcox  * If the user of the XArray prefers, they can tag their pointers instead
783159f943SMatthew Wilcox  * of storing value entries.  Three tags are available (0, 1 and 3).
793159f943SMatthew Wilcox  * These are distinct from the xa_mark_t as they are not replicated up
803159f943SMatthew Wilcox  * through the array and cannot be searched for.
813159f943SMatthew Wilcox  *
823159f943SMatthew Wilcox  * Context: Any context.
833159f943SMatthew Wilcox  * Return: An XArray entry.
843159f943SMatthew Wilcox  */
853159f943SMatthew Wilcox static inline void *xa_tag_pointer(void *p, unsigned long tag)
863159f943SMatthew Wilcox {
873159f943SMatthew Wilcox 	return (void *)((unsigned long)p | tag);
883159f943SMatthew Wilcox }
893159f943SMatthew Wilcox 
903159f943SMatthew Wilcox /**
913159f943SMatthew Wilcox  * xa_untag_pointer() - Turn an XArray entry into a plain pointer.
923159f943SMatthew Wilcox  * @entry: XArray entry.
933159f943SMatthew Wilcox  *
943159f943SMatthew Wilcox  * If you have stored a tagged pointer in the XArray, call this function
953159f943SMatthew Wilcox  * to get the untagged version of the pointer.
963159f943SMatthew Wilcox  *
973159f943SMatthew Wilcox  * Context: Any context.
983159f943SMatthew Wilcox  * Return: A pointer.
993159f943SMatthew Wilcox  */
1003159f943SMatthew Wilcox static inline void *xa_untag_pointer(void *entry)
1013159f943SMatthew Wilcox {
1023159f943SMatthew Wilcox 	return (void *)((unsigned long)entry & ~3UL);
1033159f943SMatthew Wilcox }
1043159f943SMatthew Wilcox 
1053159f943SMatthew Wilcox /**
1063159f943SMatthew Wilcox  * xa_pointer_tag() - Get the tag stored in an XArray entry.
1073159f943SMatthew Wilcox  * @entry: XArray entry.
1083159f943SMatthew Wilcox  *
1093159f943SMatthew Wilcox  * If you have stored a tagged pointer in the XArray, call this function
1103159f943SMatthew Wilcox  * to get the tag of that pointer.
1113159f943SMatthew Wilcox  *
1123159f943SMatthew Wilcox  * Context: Any context.
1133159f943SMatthew Wilcox  * Return: A tag.
1143159f943SMatthew Wilcox  */
1153159f943SMatthew Wilcox static inline unsigned int xa_pointer_tag(void *entry)
1163159f943SMatthew Wilcox {
1173159f943SMatthew Wilcox 	return (unsigned long)entry & 3UL;
1183159f943SMatthew Wilcox }
119f6bb2a2cSMatthew Wilcox 
120*02c02bf1SMatthew Wilcox /*
121*02c02bf1SMatthew Wilcox  * xa_mk_internal() - Create an internal entry.
122*02c02bf1SMatthew Wilcox  * @v: Value to turn into an internal entry.
123*02c02bf1SMatthew Wilcox  *
124*02c02bf1SMatthew Wilcox  * Context: Any context.
125*02c02bf1SMatthew Wilcox  * Return: An XArray internal entry corresponding to this value.
126*02c02bf1SMatthew Wilcox  */
127*02c02bf1SMatthew Wilcox static inline void *xa_mk_internal(unsigned long v)
128*02c02bf1SMatthew Wilcox {
129*02c02bf1SMatthew Wilcox 	return (void *)((v << 2) | 2);
130*02c02bf1SMatthew Wilcox }
131*02c02bf1SMatthew Wilcox 
132*02c02bf1SMatthew Wilcox /*
133*02c02bf1SMatthew Wilcox  * xa_to_internal() - Extract the value from an internal entry.
134*02c02bf1SMatthew Wilcox  * @entry: XArray entry.
135*02c02bf1SMatthew Wilcox  *
136*02c02bf1SMatthew Wilcox  * Context: Any context.
137*02c02bf1SMatthew Wilcox  * Return: The value which was stored in the internal entry.
138*02c02bf1SMatthew Wilcox  */
139*02c02bf1SMatthew Wilcox static inline unsigned long xa_to_internal(const void *entry)
140*02c02bf1SMatthew Wilcox {
141*02c02bf1SMatthew Wilcox 	return (unsigned long)entry >> 2;
142*02c02bf1SMatthew Wilcox }
143*02c02bf1SMatthew Wilcox 
144*02c02bf1SMatthew Wilcox /*
145*02c02bf1SMatthew Wilcox  * xa_is_internal() - Is the entry an internal entry?
146*02c02bf1SMatthew Wilcox  * @entry: XArray entry.
147*02c02bf1SMatthew Wilcox  *
148*02c02bf1SMatthew Wilcox  * Context: Any context.
149*02c02bf1SMatthew Wilcox  * Return: %true if the entry is an internal entry.
150*02c02bf1SMatthew Wilcox  */
151*02c02bf1SMatthew Wilcox static inline bool xa_is_internal(const void *entry)
152*02c02bf1SMatthew Wilcox {
153*02c02bf1SMatthew Wilcox 	return ((unsigned long)entry & 3) == 2;
154*02c02bf1SMatthew Wilcox }
155*02c02bf1SMatthew Wilcox 
156f6bb2a2cSMatthew Wilcox #define xa_trylock(xa)		spin_trylock(&(xa)->xa_lock)
157f6bb2a2cSMatthew Wilcox #define xa_lock(xa)		spin_lock(&(xa)->xa_lock)
158f6bb2a2cSMatthew Wilcox #define xa_unlock(xa)		spin_unlock(&(xa)->xa_lock)
159f6bb2a2cSMatthew Wilcox #define xa_lock_bh(xa)		spin_lock_bh(&(xa)->xa_lock)
160f6bb2a2cSMatthew Wilcox #define xa_unlock_bh(xa)	spin_unlock_bh(&(xa)->xa_lock)
161f6bb2a2cSMatthew Wilcox #define xa_lock_irq(xa)		spin_lock_irq(&(xa)->xa_lock)
162f6bb2a2cSMatthew Wilcox #define xa_unlock_irq(xa)	spin_unlock_irq(&(xa)->xa_lock)
163f6bb2a2cSMatthew Wilcox #define xa_lock_irqsave(xa, flags) \
164f6bb2a2cSMatthew Wilcox 				spin_lock_irqsave(&(xa)->xa_lock, flags)
165f6bb2a2cSMatthew Wilcox #define xa_unlock_irqrestore(xa, flags) \
166f6bb2a2cSMatthew Wilcox 				spin_unlock_irqrestore(&(xa)->xa_lock, flags)
167f6bb2a2cSMatthew Wilcox 
168*02c02bf1SMatthew Wilcox /* Everything below here is the Advanced API.  Proceed with caution. */
169*02c02bf1SMatthew Wilcox 
170*02c02bf1SMatthew Wilcox /*
171*02c02bf1SMatthew Wilcox  * The xarray is constructed out of a set of 'chunks' of pointers.  Choosing
172*02c02bf1SMatthew Wilcox  * the best chunk size requires some tradeoffs.  A power of two recommends
173*02c02bf1SMatthew Wilcox  * itself so that we can walk the tree based purely on shifts and masks.
174*02c02bf1SMatthew Wilcox  * Generally, the larger the better; as the number of slots per level of the
175*02c02bf1SMatthew Wilcox  * tree increases, the less tall the tree needs to be.  But that needs to be
176*02c02bf1SMatthew Wilcox  * balanced against the memory consumption of each node.  On a 64-bit system,
177*02c02bf1SMatthew Wilcox  * xa_node is currently 576 bytes, and we get 7 of them per 4kB page.  If we
178*02c02bf1SMatthew Wilcox  * doubled the number of slots per node, we'd get only 3 nodes per 4kB page.
179*02c02bf1SMatthew Wilcox  */
180*02c02bf1SMatthew Wilcox #ifndef XA_CHUNK_SHIFT
181*02c02bf1SMatthew Wilcox #define XA_CHUNK_SHIFT		(CONFIG_BASE_SMALL ? 4 : 6)
182*02c02bf1SMatthew Wilcox #endif
183*02c02bf1SMatthew Wilcox #define XA_CHUNK_SIZE		(1UL << XA_CHUNK_SHIFT)
184*02c02bf1SMatthew Wilcox #define XA_CHUNK_MASK		(XA_CHUNK_SIZE - 1)
185*02c02bf1SMatthew Wilcox 
186*02c02bf1SMatthew Wilcox /* Private */
187*02c02bf1SMatthew Wilcox static inline bool xa_is_node(const void *entry)
188*02c02bf1SMatthew Wilcox {
189*02c02bf1SMatthew Wilcox 	return xa_is_internal(entry) && (unsigned long)entry > 4096;
190*02c02bf1SMatthew Wilcox }
191*02c02bf1SMatthew Wilcox 
192*02c02bf1SMatthew Wilcox /* Private */
193*02c02bf1SMatthew Wilcox static inline void *xa_mk_sibling(unsigned int offset)
194*02c02bf1SMatthew Wilcox {
195*02c02bf1SMatthew Wilcox 	return xa_mk_internal(offset);
196*02c02bf1SMatthew Wilcox }
197*02c02bf1SMatthew Wilcox 
198*02c02bf1SMatthew Wilcox /* Private */
199*02c02bf1SMatthew Wilcox static inline unsigned long xa_to_sibling(const void *entry)
200*02c02bf1SMatthew Wilcox {
201*02c02bf1SMatthew Wilcox 	return xa_to_internal(entry);
202*02c02bf1SMatthew Wilcox }
203*02c02bf1SMatthew Wilcox 
204*02c02bf1SMatthew Wilcox /**
205*02c02bf1SMatthew Wilcox  * xa_is_sibling() - Is the entry a sibling entry?
206*02c02bf1SMatthew Wilcox  * @entry: Entry retrieved from the XArray
207*02c02bf1SMatthew Wilcox  *
208*02c02bf1SMatthew Wilcox  * Return: %true if the entry is a sibling entry.
209*02c02bf1SMatthew Wilcox  */
210*02c02bf1SMatthew Wilcox static inline bool xa_is_sibling(const void *entry)
211*02c02bf1SMatthew Wilcox {
212*02c02bf1SMatthew Wilcox 	return IS_ENABLED(CONFIG_XARRAY_MULTI) && xa_is_internal(entry) &&
213*02c02bf1SMatthew Wilcox 		(entry < xa_mk_sibling(XA_CHUNK_SIZE - 1));
214*02c02bf1SMatthew Wilcox }
215*02c02bf1SMatthew Wilcox 
216*02c02bf1SMatthew Wilcox #define XA_RETRY_ENTRY		xa_mk_internal(256)
217*02c02bf1SMatthew Wilcox 
218f6bb2a2cSMatthew Wilcox #endif /* _LINUX_XARRAY_H */
219