xref: /openbmc/linux/Documentation/core-api/maple_tree.rst (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*54a611b6SLiam R. Howlett.. SPDX-License-Identifier: GPL-2.0+
2*54a611b6SLiam R. Howlett
3*54a611b6SLiam R. Howlett
4*54a611b6SLiam R. Howlett==========
5*54a611b6SLiam R. HowlettMaple Tree
6*54a611b6SLiam R. Howlett==========
7*54a611b6SLiam R. Howlett
8*54a611b6SLiam R. Howlett:Author: Liam R. Howlett
9*54a611b6SLiam R. Howlett
10*54a611b6SLiam R. HowlettOverview
11*54a611b6SLiam R. Howlett========
12*54a611b6SLiam R. Howlett
13*54a611b6SLiam R. HowlettThe Maple Tree is a B-Tree data type which is optimized for storing
14*54a611b6SLiam R. Howlettnon-overlapping ranges, including ranges of size 1.  The tree was designed to
15*54a611b6SLiam R. Howlettbe simple to use and does not require a user written search method.  It
16*54a611b6SLiam R. Howlettsupports iterating over a range of entries and going to the previous or next
17*54a611b6SLiam R. Howlettentry in a cache-efficient manner.  The tree can also be put into an RCU-safe
18*54a611b6SLiam R. Howlettmode of operation which allows reading and writing concurrently.  Writers must
19*54a611b6SLiam R. Howlettsynchronize on a lock, which can be the default spinlock, or the user can set
20*54a611b6SLiam R. Howlettthe lock to an external lock of a different type.
21*54a611b6SLiam R. Howlett
22*54a611b6SLiam R. HowlettThe Maple Tree maintains a small memory footprint and was designed to use
23*54a611b6SLiam R. Howlettmodern processor cache efficiently.  The majority of the users will be able to
24*54a611b6SLiam R. Howlettuse the normal API.  An :ref:`maple-tree-advanced-api` exists for more complex
25*54a611b6SLiam R. Howlettscenarios.  The most important usage of the Maple Tree is the tracking of the
26*54a611b6SLiam R. Howlettvirtual memory areas.
27*54a611b6SLiam R. Howlett
28*54a611b6SLiam R. HowlettThe Maple Tree can store values between ``0`` and ``ULONG_MAX``.  The Maple
29*54a611b6SLiam R. HowlettTree reserves values with the bottom two bits set to '10' which are below 4096
30*54a611b6SLiam R. Howlett(ie 2, 6, 10 .. 4094) for internal use.  If the entries may use reserved
31*54a611b6SLiam R. Howlettentries then the users can convert the entries using xa_mk_value() and convert
32*54a611b6SLiam R. Howlettthem back by calling xa_to_value().  If the user needs to use a reserved
33*54a611b6SLiam R. Howlettvalue, then the user can convert the value when using the
34*54a611b6SLiam R. Howlett:ref:`maple-tree-advanced-api`, but are blocked by the normal API.
35*54a611b6SLiam R. Howlett
36*54a611b6SLiam R. HowlettThe Maple Tree can also be configured to support searching for a gap of a given
37*54a611b6SLiam R. Howlettsize (or larger).
38*54a611b6SLiam R. Howlett
39*54a611b6SLiam R. HowlettPre-allocating of nodes is also supported using the
40*54a611b6SLiam R. Howlett:ref:`maple-tree-advanced-api`.  This is useful for users who must guarantee a
41*54a611b6SLiam R. Howlettsuccessful store operation within a given
42*54a611b6SLiam R. Howlettcode segment when allocating cannot be done.  Allocations of nodes are
43*54a611b6SLiam R. Howlettrelatively small at around 256 bytes.
44*54a611b6SLiam R. Howlett
45*54a611b6SLiam R. Howlett.. _maple-tree-normal-api:
46*54a611b6SLiam R. Howlett
47*54a611b6SLiam R. HowlettNormal API
48*54a611b6SLiam R. Howlett==========
49*54a611b6SLiam R. Howlett
50*54a611b6SLiam R. HowlettStart by initialising a maple tree, either with DEFINE_MTREE() for statically
51*54a611b6SLiam R. Howlettallocated maple trees or mt_init() for dynamically allocated ones.  A
52*54a611b6SLiam R. Howlettfreshly-initialised maple tree contains a ``NULL`` pointer for the range ``0``
53*54a611b6SLiam R. Howlett- ``ULONG_MAX``.  There are currently two types of maple trees supported: the
54*54a611b6SLiam R. Howlettallocation tree and the regular tree.  The regular tree has a higher branching
55*54a611b6SLiam R. Howlettfactor for internal nodes.  The allocation tree has a lower branching factor
56*54a611b6SLiam R. Howlettbut allows the user to search for a gap of a given size or larger from either
57*54a611b6SLiam R. Howlett``0`` upwards or ``ULONG_MAX`` down.  An allocation tree can be used by
58*54a611b6SLiam R. Howlettpassing in the ``MT_FLAGS_ALLOC_RANGE`` flag when initialising the tree.
59*54a611b6SLiam R. Howlett
60*54a611b6SLiam R. HowlettYou can then set entries using mtree_store() or mtree_store_range().
61*54a611b6SLiam R. Howlettmtree_store() will overwrite any entry with the new entry and return 0 on
62*54a611b6SLiam R. Howlettsuccess or an error code otherwise.  mtree_store_range() works in the same way
63*54a611b6SLiam R. Howlettbut takes a range.  mtree_load() is used to retrieve the entry stored at a
64*54a611b6SLiam R. Howlettgiven index.  You can use mtree_erase() to erase an entire range by only
65*54a611b6SLiam R. Howlettknowing one value within that range, or mtree_store() call with an entry of
66*54a611b6SLiam R. HowlettNULL may be used to partially erase a range or many ranges at once.
67*54a611b6SLiam R. Howlett
68*54a611b6SLiam R. HowlettIf you want to only store a new entry to a range (or index) if that range is
69*54a611b6SLiam R. Howlettcurrently ``NULL``, you can use mtree_insert_range() or mtree_insert() which
70*54a611b6SLiam R. Howlettreturn -EEXIST if the range is not empty.
71*54a611b6SLiam R. Howlett
72*54a611b6SLiam R. HowlettYou can search for an entry from an index upwards by using mt_find().
73*54a611b6SLiam R. Howlett
74*54a611b6SLiam R. HowlettYou can walk each entry within a range by calling mt_for_each().  You must
75*54a611b6SLiam R. Howlettprovide a temporary variable to store a cursor.  If you want to walk each
76*54a611b6SLiam R. Howlettelement of the tree then ``0`` and ``ULONG_MAX`` may be used as the range.  If
77*54a611b6SLiam R. Howlettthe caller is going to hold the lock for the duration of the walk then it is
78*54a611b6SLiam R. Howlettworth looking at the mas_for_each() API in the :ref:`maple-tree-advanced-api`
79*54a611b6SLiam R. Howlettsection.
80*54a611b6SLiam R. Howlett
81*54a611b6SLiam R. HowlettSometimes it is necessary to ensure the next call to store to a maple tree does
82*54a611b6SLiam R. Howlettnot allocate memory, please see :ref:`maple-tree-advanced-api` for this use case.
83*54a611b6SLiam R. Howlett
84*54a611b6SLiam R. HowlettFinally, you can remove all entries from a maple tree by calling
85*54a611b6SLiam R. Howlettmtree_destroy().  If the maple tree entries are pointers, you may wish to free
86*54a611b6SLiam R. Howlettthe entries first.
87*54a611b6SLiam R. Howlett
88*54a611b6SLiam R. HowlettAllocating Nodes
89*54a611b6SLiam R. Howlett----------------
90*54a611b6SLiam R. Howlett
91*54a611b6SLiam R. HowlettThe allocations are handled by the internal tree code.  See
92*54a611b6SLiam R. Howlett:ref:`maple-tree-advanced-alloc` for other options.
93*54a611b6SLiam R. Howlett
94*54a611b6SLiam R. HowlettLocking
95*54a611b6SLiam R. Howlett-------
96*54a611b6SLiam R. Howlett
97*54a611b6SLiam R. HowlettYou do not have to worry about locking.  See :ref:`maple-tree-advanced-locks`
98*54a611b6SLiam R. Howlettfor other options.
99*54a611b6SLiam R. Howlett
100*54a611b6SLiam R. HowlettThe Maple Tree uses RCU and an internal spinlock to synchronise access:
101*54a611b6SLiam R. Howlett
102*54a611b6SLiam R. HowlettTakes RCU read lock:
103*54a611b6SLiam R. Howlett * mtree_load()
104*54a611b6SLiam R. Howlett * mt_find()
105*54a611b6SLiam R. Howlett * mt_for_each()
106*54a611b6SLiam R. Howlett * mt_next()
107*54a611b6SLiam R. Howlett * mt_prev()
108*54a611b6SLiam R. Howlett
109*54a611b6SLiam R. HowlettTakes ma_lock internally:
110*54a611b6SLiam R. Howlett * mtree_store()
111*54a611b6SLiam R. Howlett * mtree_store_range()
112*54a611b6SLiam R. Howlett * mtree_insert()
113*54a611b6SLiam R. Howlett * mtree_insert_range()
114*54a611b6SLiam R. Howlett * mtree_erase()
115*54a611b6SLiam R. Howlett * mtree_destroy()
116*54a611b6SLiam R. Howlett * mt_set_in_rcu()
117*54a611b6SLiam R. Howlett * mt_clear_in_rcu()
118*54a611b6SLiam R. Howlett
119*54a611b6SLiam R. HowlettIf you want to take advantage of the internal lock to protect the data
120*54a611b6SLiam R. Howlettstructures that you are storing in the Maple Tree, you can call mtree_lock()
121*54a611b6SLiam R. Howlettbefore calling mtree_load(), then take a reference count on the object you
122*54a611b6SLiam R. Howletthave found before calling mtree_unlock().  This will prevent stores from
123*54a611b6SLiam R. Howlettremoving the object from the tree between looking up the object and
124*54a611b6SLiam R. Howlettincrementing the refcount.  You can also use RCU to avoid dereferencing
125*54a611b6SLiam R. Howlettfreed memory, but an explanation of that is beyond the scope of this
126*54a611b6SLiam R. Howlettdocument.
127*54a611b6SLiam R. Howlett
128*54a611b6SLiam R. Howlett.. _maple-tree-advanced-api:
129*54a611b6SLiam R. Howlett
130*54a611b6SLiam R. HowlettAdvanced API
131*54a611b6SLiam R. Howlett============
132*54a611b6SLiam R. Howlett
133*54a611b6SLiam R. HowlettThe advanced API offers more flexibility and better performance at the
134*54a611b6SLiam R. Howlettcost of an interface which can be harder to use and has fewer safeguards.
135*54a611b6SLiam R. HowlettYou must take care of your own locking while using the advanced API.
136*54a611b6SLiam R. HowlettYou can use the ma_lock, RCU or an external lock for protection.
137*54a611b6SLiam R. HowlettYou can mix advanced and normal operations on the same array, as long
138*54a611b6SLiam R. Howlettas the locking is compatible.  The :ref:`maple-tree-normal-api` is implemented
139*54a611b6SLiam R. Howlettin terms of the advanced API.
140*54a611b6SLiam R. Howlett
141*54a611b6SLiam R. HowlettThe advanced API is based around the ma_state, this is where the 'mas'
142*54a611b6SLiam R. Howlettprefix originates.  The ma_state struct keeps track of tree operations to make
143*54a611b6SLiam R. Howlettlife easier for both internal and external tree users.
144*54a611b6SLiam R. Howlett
145*54a611b6SLiam R. HowlettInitialising the maple tree is the same as in the :ref:`maple-tree-normal-api`.
146*54a611b6SLiam R. HowlettPlease see above.
147*54a611b6SLiam R. Howlett
148*54a611b6SLiam R. HowlettThe maple state keeps track of the range start and end in mas->index and
149*54a611b6SLiam R. Howlettmas->last, respectively.
150*54a611b6SLiam R. Howlett
151*54a611b6SLiam R. Howlettmas_walk() will walk the tree to the location of mas->index and set the
152*54a611b6SLiam R. Howlettmas->index and mas->last according to the range for the entry.
153*54a611b6SLiam R. Howlett
154*54a611b6SLiam R. HowlettYou can set entries using mas_store().  mas_store() will overwrite any entry
155*54a611b6SLiam R. Howlettwith the new entry and return the first existing entry that is overwritten.
156*54a611b6SLiam R. HowlettThe range is passed in as members of the maple state: index and last.
157*54a611b6SLiam R. Howlett
158*54a611b6SLiam R. HowlettYou can use mas_erase() to erase an entire range by setting index and
159*54a611b6SLiam R. Howlettlast of the maple state to the desired range to erase.  This will erase
160*54a611b6SLiam R. Howlettthe first range that is found in that range, set the maple state index
161*54a611b6SLiam R. Howlettand last as the range that was erased and return the entry that existed
162*54a611b6SLiam R. Howlettat that location.
163*54a611b6SLiam R. Howlett
164*54a611b6SLiam R. HowlettYou can walk each entry within a range by using mas_for_each().  If you want
165*54a611b6SLiam R. Howlettto walk each element of the tree then ``0`` and ``ULONG_MAX`` may be used as
166*54a611b6SLiam R. Howlettthe range.  If the lock needs to be periodically dropped, see the locking
167*54a611b6SLiam R. Howlettsection mas_pause().
168*54a611b6SLiam R. Howlett
169*54a611b6SLiam R. HowlettUsing a maple state allows mas_next() and mas_prev() to function as if the
170*54a611b6SLiam R. Howletttree was a linked list.  With such a high branching factor the amortized
171*54a611b6SLiam R. Howlettperformance penalty is outweighed by cache optimization.  mas_next() will
172*54a611b6SLiam R. Howlettreturn the next entry which occurs after the entry at index.  mas_prev()
173*54a611b6SLiam R. Howlettwill return the previous entry which occurs before the entry at index.
174*54a611b6SLiam R. Howlett
175*54a611b6SLiam R. Howlettmas_find() will find the first entry which exists at or above index on
176*54a611b6SLiam R. Howlettthe first call, and the next entry from every subsequent calls.
177*54a611b6SLiam R. Howlett
178*54a611b6SLiam R. Howlettmas_find_rev() will find the fist entry which exists at or below the last on
179*54a611b6SLiam R. Howlettthe first call, and the previous entry from every subsequent calls.
180*54a611b6SLiam R. Howlett
181*54a611b6SLiam R. HowlettIf the user needs to yield the lock during an operation, then the maple state
182*54a611b6SLiam R. Howlettmust be paused using mas_pause().
183*54a611b6SLiam R. Howlett
184*54a611b6SLiam R. HowlettThere are a few extra interfaces provided when using an allocation tree.
185*54a611b6SLiam R. HowlettIf you wish to search for a gap within a range, then mas_empty_area()
186*54a611b6SLiam R. Howlettor mas_empty_area_rev() can be used.  mas_empty_area() searches for a gap
187*54a611b6SLiam R. Howlettstarting at the lowest index given up to the maximum of the range.
188*54a611b6SLiam R. Howlettmas_empty_area_rev() searches for a gap starting at the highest index given
189*54a611b6SLiam R. Howlettand continues downward to the lower bound of the range.
190*54a611b6SLiam R. Howlett
191*54a611b6SLiam R. Howlett.. _maple-tree-advanced-alloc:
192*54a611b6SLiam R. Howlett
193*54a611b6SLiam R. HowlettAdvanced Allocating Nodes
194*54a611b6SLiam R. Howlett-------------------------
195*54a611b6SLiam R. Howlett
196*54a611b6SLiam R. HowlettAllocations are usually handled internally to the tree, however if allocations
197*54a611b6SLiam R. Howlettneed to occur before a write occurs then calling mas_expected_entries() will
198*54a611b6SLiam R. Howlettallocate the worst-case number of needed nodes to insert the provided number of
199*54a611b6SLiam R. Howlettranges.  This also causes the tree to enter mass insertion mode.  Once
200*54a611b6SLiam R. Howlettinsertions are complete calling mas_destroy() on the maple state will free the
201*54a611b6SLiam R. Howlettunused allocations.
202*54a611b6SLiam R. Howlett
203*54a611b6SLiam R. Howlett.. _maple-tree-advanced-locks:
204*54a611b6SLiam R. Howlett
205*54a611b6SLiam R. HowlettAdvanced Locking
206*54a611b6SLiam R. Howlett----------------
207*54a611b6SLiam R. Howlett
208*54a611b6SLiam R. HowlettThe maple tree uses a spinlock by default, but external locks can be used for
209*54a611b6SLiam R. Howletttree updates as well.  To use an external lock, the tree must be initialized
210*54a611b6SLiam R. Howlettwith the ``MT_FLAGS_LOCK_EXTERN flag``, this is usually done with the
211*54a611b6SLiam R. HowlettMTREE_INIT_EXT() #define, which takes an external lock as an argument.
212*54a611b6SLiam R. Howlett
213*54a611b6SLiam R. HowlettFunctions and structures
214*54a611b6SLiam R. Howlett========================
215*54a611b6SLiam R. Howlett
216*54a611b6SLiam R. Howlett.. kernel-doc:: include/linux/maple_tree.h
217*54a611b6SLiam R. Howlett.. kernel-doc:: lib/maple_tree.c
218