summaryrefslogtreecommitdiffstats
path: root/include/linux/xarray.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/xarray.h')
-rw-r--r--include/linux/xarray.h92
1 files changed, 92 insertions, 0 deletions
diff --git a/include/linux/xarray.h b/include/linux/xarray.h
index 5c8acfc4ff55..4d1cd7a083e8 100644
--- a/include/linux/xarray.h
+++ b/include/linux/xarray.h
@@ -22,6 +22,12 @@
22 * x1: Value entry or tagged pointer 22 * x1: Value entry or tagged pointer
23 * 23 *
24 * Attempting to store internal entries in the XArray is a bug. 24 * Attempting to store internal entries in the XArray is a bug.
25 *
26 * Most internal entries are pointers to the next node in the tree.
27 * The following internal entries have a special meaning:
28 *
29 * 0-62: Sibling entries
30 * 256: Retry entry
25 */ 31 */
26 32
27#define BITS_PER_XA_VALUE (BITS_PER_LONG - 1) 33#define BITS_PER_XA_VALUE (BITS_PER_LONG - 1)
@@ -111,6 +117,42 @@ static inline unsigned int xa_pointer_tag(void *entry)
111 return (unsigned long)entry & 3UL; 117 return (unsigned long)entry & 3UL;
112} 118}
113 119
120/*
121 * xa_mk_internal() - Create an internal entry.
122 * @v: Value to turn into an internal entry.
123 *
124 * Context: Any context.
125 * Return: An XArray internal entry corresponding to this value.
126 */
127static inline void *xa_mk_internal(unsigned long v)
128{
129 return (void *)((v << 2) | 2);
130}
131
132/*
133 * xa_to_internal() - Extract the value from an internal entry.
134 * @entry: XArray entry.
135 *
136 * Context: Any context.
137 * Return: The value which was stored in the internal entry.
138 */
139static inline unsigned long xa_to_internal(const void *entry)
140{
141 return (unsigned long)entry >> 2;
142}
143
144/*
145 * xa_is_internal() - Is the entry an internal entry?
146 * @entry: XArray entry.
147 *
148 * Context: Any context.
149 * Return: %true if the entry is an internal entry.
150 */
151static inline bool xa_is_internal(const void *entry)
152{
153 return ((unsigned long)entry & 3) == 2;
154}
155
114#define xa_trylock(xa) spin_trylock(&(xa)->xa_lock) 156#define xa_trylock(xa) spin_trylock(&(xa)->xa_lock)
115#define xa_lock(xa) spin_lock(&(xa)->xa_lock) 157#define xa_lock(xa) spin_lock(&(xa)->xa_lock)
116#define xa_unlock(xa) spin_unlock(&(xa)->xa_lock) 158#define xa_unlock(xa) spin_unlock(&(xa)->xa_lock)
@@ -123,4 +165,54 @@ static inline unsigned int xa_pointer_tag(void *entry)
123#define xa_unlock_irqrestore(xa, flags) \ 165#define xa_unlock_irqrestore(xa, flags) \
124 spin_unlock_irqrestore(&(xa)->xa_lock, flags) 166 spin_unlock_irqrestore(&(xa)->xa_lock, flags)
125 167
168/* Everything below here is the Advanced API. Proceed with caution. */
169
170/*
171 * The xarray is constructed out of a set of 'chunks' of pointers. Choosing
172 * the best chunk size requires some tradeoffs. A power of two recommends
173 * itself so that we can walk the tree based purely on shifts and masks.
174 * Generally, the larger the better; as the number of slots per level of the
175 * tree increases, the less tall the tree needs to be. But that needs to be
176 * balanced against the memory consumption of each node. On a 64-bit system,
177 * xa_node is currently 576 bytes, and we get 7 of them per 4kB page. If we
178 * doubled the number of slots per node, we'd get only 3 nodes per 4kB page.
179 */
180#ifndef XA_CHUNK_SHIFT
181#define XA_CHUNK_SHIFT (CONFIG_BASE_SMALL ? 4 : 6)
182#endif
183#define XA_CHUNK_SIZE (1UL << XA_CHUNK_SHIFT)
184#define XA_CHUNK_MASK (XA_CHUNK_SIZE - 1)
185
186/* Private */
187static inline bool xa_is_node(const void *entry)
188{
189 return xa_is_internal(entry) && (unsigned long)entry > 4096;
190}
191
192/* Private */
193static inline void *xa_mk_sibling(unsigned int offset)
194{
195 return xa_mk_internal(offset);
196}
197
198/* Private */
199static inline unsigned long xa_to_sibling(const void *entry)
200{
201 return xa_to_internal(entry);
202}
203
204/**
205 * xa_is_sibling() - Is the entry a sibling entry?
206 * @entry: Entry retrieved from the XArray
207 *
208 * Return: %true if the entry is a sibling entry.
209 */
210static inline bool xa_is_sibling(const void *entry)
211{
212 return IS_ENABLED(CONFIG_XARRAY_MULTI) && xa_is_internal(entry) &&
213 (entry < xa_mk_sibling(XA_CHUNK_SIZE - 1));
214}
215
216#define XA_RETRY_ENTRY xa_mk_internal(256)
217
126#endif /* _LINUX_XARRAY_H */ 218#endif /* _LINUX_XARRAY_H */