blob: 4d1cd7a083e88e67bc1a43b485a66bba174f8a1b [file] [log] [blame]
Matthew Wilcoxf6bb2a22018-04-10 16:36:52 -07001/* SPDX-License-Identifier: GPL-2.0+ */
2#ifndef _LINUX_XARRAY_H
3#define _LINUX_XARRAY_H
4/*
5 * eXtensible Arrays
6 * Copyright (c) 2017 Microsoft Corporation
Matthew Wilcox3d0186b2018-06-16 17:32:07 -04007 * Author: Matthew Wilcox <willy@infradead.org>
Matthew Wilcox3159f942017-11-03 13:30:42 -04008 *
9 * See Documentation/core-api/xarray.rst for how to use the XArray.
Matthew Wilcoxf6bb2a22018-04-10 16:36:52 -070010 */
11
Matthew Wilcox3159f942017-11-03 13:30:42 -040012#include <linux/bug.h>
Matthew Wilcoxf6bb2a22018-04-10 16:36:52 -070013#include <linux/spinlock.h>
Matthew Wilcox3159f942017-11-03 13:30:42 -040014#include <linux/types.h>
15
16/*
17 * The bottom two bits of the entry determine how the XArray interprets
18 * the contents:
19 *
20 * 00: Pointer entry
21 * 10: Internal entry
22 * x1: Value entry or tagged pointer
23 *
24 * Attempting to store internal entries in the XArray is a bug.
Matthew Wilcox02c02bf2017-11-03 23:09:45 -040025 *
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
Matthew Wilcox3159f942017-11-03 13:30:42 -040031 */
32
33#define BITS_PER_XA_VALUE (BITS_PER_LONG - 1)
34
35/**
36 * xa_mk_value() - Create an XArray entry from an integer.
37 * @v: Value to store in XArray.
38 *
39 * Context: Any context.
40 * Return: An entry suitable for storing in the XArray.
41 */
42static inline void *xa_mk_value(unsigned long v)
43{
44 WARN_ON((long)v < 0);
45 return (void *)((v << 1) | 1);
46}
47
48/**
49 * xa_to_value() - Get value stored in an XArray entry.
50 * @entry: XArray entry.
51 *
52 * Context: Any context.
53 * Return: The value stored in the XArray entry.
54 */
55static inline unsigned long xa_to_value(const void *entry)
56{
57 return (unsigned long)entry >> 1;
58}
59
60/**
61 * xa_is_value() - Determine if an entry is a value.
62 * @entry: XArray entry.
63 *
64 * Context: Any context.
65 * Return: True if the entry is a value, false if it is a pointer.
66 */
67static inline bool xa_is_value(const void *entry)
68{
69 return (unsigned long)entry & 1;
70}
71
72/**
73 * xa_tag_pointer() - Create an XArray entry for a tagged pointer.
74 * @p: Plain pointer.
75 * @tag: Tag value (0, 1 or 3).
76 *
77 * If the user of the XArray prefers, they can tag their pointers instead
78 * of storing value entries. Three tags are available (0, 1 and 3).
79 * These are distinct from the xa_mark_t as they are not replicated up
80 * through the array and cannot be searched for.
81 *
82 * Context: Any context.
83 * Return: An XArray entry.
84 */
85static inline void *xa_tag_pointer(void *p, unsigned long tag)
86{
87 return (void *)((unsigned long)p | tag);
88}
89
90/**
91 * xa_untag_pointer() - Turn an XArray entry into a plain pointer.
92 * @entry: XArray entry.
93 *
94 * If you have stored a tagged pointer in the XArray, call this function
95 * to get the untagged version of the pointer.
96 *
97 * Context: Any context.
98 * Return: A pointer.
99 */
100static inline void *xa_untag_pointer(void *entry)
101{
102 return (void *)((unsigned long)entry & ~3UL);
103}
104
105/**
106 * xa_pointer_tag() - Get the tag stored in an XArray entry.
107 * @entry: XArray entry.
108 *
109 * If you have stored a tagged pointer in the XArray, call this function
110 * to get the tag of that pointer.
111 *
112 * Context: Any context.
113 * Return: A tag.
114 */
115static inline unsigned int xa_pointer_tag(void *entry)
116{
117 return (unsigned long)entry & 3UL;
118}
Matthew Wilcoxf6bb2a22018-04-10 16:36:52 -0700119
Matthew Wilcox02c02bf2017-11-03 23:09:45 -0400120/*
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
Matthew Wilcoxf6bb2a22018-04-10 16:36:52 -0700156#define xa_trylock(xa) spin_trylock(&(xa)->xa_lock)
157#define xa_lock(xa) spin_lock(&(xa)->xa_lock)
158#define xa_unlock(xa) spin_unlock(&(xa)->xa_lock)
159#define xa_lock_bh(xa) spin_lock_bh(&(xa)->xa_lock)
160#define xa_unlock_bh(xa) spin_unlock_bh(&(xa)->xa_lock)
161#define xa_lock_irq(xa) spin_lock_irq(&(xa)->xa_lock)
162#define xa_unlock_irq(xa) spin_unlock_irq(&(xa)->xa_lock)
163#define xa_lock_irqsave(xa, flags) \
164 spin_lock_irqsave(&(xa)->xa_lock, flags)
165#define xa_unlock_irqrestore(xa, flags) \
166 spin_unlock_irqrestore(&(xa)->xa_lock, flags)
167
Matthew Wilcox02c02bf2017-11-03 23:09:45 -0400168/* 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
Matthew Wilcoxf6bb2a22018-04-10 16:36:52 -0700218#endif /* _LINUX_XARRAY_H */