Merge tag 'xarray-5.18' of git://git.infradead.org/users/willy/xarray
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Apr 2022 20:40:44 +0000 (13:40 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Apr 2022 20:40:44 +0000 (13:40 -0700)
Pull XArray updates from Matthew Wilcox:

 - Documentation update

 - Fix test-suite build after move of bitmap.h

 - Fix xas_create_range() when a large entry is already present

 - Fix xas_split() of a shadow entry

* tag 'xarray-5.18' of git://git.infradead.org/users/willy/xarray:
  XArray: Update the LRU list in xas_split()
  XArray: Fix xas_create_range() when multi-order entry present
  XArray: Include bitmap.h from xarray.h
  XArray: Document the locking requirement for the xa_state

Documentation/core-api/xarray.rst
include/linux/xarray.h
lib/test_xarray.c
lib/xarray.c

index a137a0e6d0682038b9b578489937834e9c2b5e49..77e0ece2b1d6f8e632e7d28d17fd1c60fcf0b5c4 100644 (file)
@@ -315,11 +315,15 @@ indeed the normal API is implemented in terms of the advanced API.  The
 advanced API is only available to modules with a GPL-compatible license.
 
 The advanced API is based around the xa_state.  This is an opaque data
-structure which you declare on the stack using the XA_STATE()
-macro.  This macro initialises the xa_state ready to start walking
-around the XArray.  It is used as a cursor to maintain the position
-in the XArray and let you compose various operations together without
-having to restart from the top every time.
+structure which you declare on the stack using the XA_STATE() macro.
+This macro initialises the xa_state ready to start walking around the
+XArray.  It is used as a cursor to maintain the position in the XArray
+and let you compose various operations together without having to restart
+from the top every time.  The contents of the xa_state are protected by
+the rcu_read_lock() or the xas_lock().  If you need to drop whichever of
+those locks is protecting your state and tree, you must call xas_pause()
+so that future calls do not rely on the parts of the state which were
+left unprotected.
 
 The xa_state is also used to store errors.  You can call
 xas_error() to retrieve the error.  All operations check whether
index bb52b786be1b74b65b0ad0a55d2ecd81f44f5351..72feab5ea8d4a94d49ed48c531e2d74e9dbaac1d 100644 (file)
@@ -9,6 +9,7 @@
  * See Documentation/core-api/xarray.rst for how to use the XArray.
  */
 
+#include <linux/bitmap.h>
 #include <linux/bug.h>
 #include <linux/compiler.h>
 #include <linux/gfp.h>
index 8b1c318189ce801a0935133b4882556fede5bfd2..e77d4856442c3f750434e37819e13688d210048e 100644 (file)
@@ -1463,6 +1463,25 @@ unlock:
        XA_BUG_ON(xa, !xa_empty(xa));
 }
 
+static noinline void check_create_range_5(struct xarray *xa,
+               unsigned long index, unsigned int order)
+{
+       XA_STATE_ORDER(xas, xa, index, order);
+       unsigned int i;
+
+       xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL);
+
+       for (i = 0; i < order + 10; i++) {
+               do {
+                       xas_lock(&xas);
+                       xas_create_range(&xas);
+                       xas_unlock(&xas);
+               } while (xas_nomem(&xas, GFP_KERNEL));
+       }
+
+       xa_destroy(xa);
+}
+
 static noinline void check_create_range(struct xarray *xa)
 {
        unsigned int order;
@@ -1490,6 +1509,9 @@ static noinline void check_create_range(struct xarray *xa)
                check_create_range_4(xa, (3U << order) + 1, order);
                check_create_range_4(xa, (3U << order) - 1, order);
                check_create_range_4(xa, (1U << 24) + 1, order);
+
+               check_create_range_5(xa, 0, order);
+               check_create_range_5(xa, (1U << order), order);
        }
 
        check_create_range_3();
index b95e92598b9c4ed00b1a47f28d38b694ac8f5b81..4acc88ea7c21744e6b1faa54af6f2029545a1b32 100644 (file)
@@ -722,6 +722,8 @@ void xas_create_range(struct xa_state *xas)
 
                for (;;) {
                        struct xa_node *node = xas->xa_node;
+                       if (node->shift >= shift)
+                               break;
                        xas->xa_node = xa_parent_locked(xas->xa, node);
                        xas->xa_offset = node->offset - 1;
                        if (node->offset != 0)
@@ -1079,6 +1081,7 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order)
                                        xa_mk_node(child));
                        if (xa_is_value(curr))
                                values--;
+                       xas_update(xas, child);
                } else {
                        unsigned int canon = offset - xas->xa_sibs;
 
@@ -1093,6 +1096,7 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order)
        } while (offset-- > xas->xa_offset);
 
        node->nr_values += values;
+       xas_update(xas, node);
 }
 EXPORT_SYMBOL_GPL(xas_split);
 #endif