diff options
author | Matthew Wilcox <willy@infradead.org> | 2019-02-21 17:36:45 -0500 |
---|---|---|
committer | Matthew Wilcox <willy@infradead.org> | 2019-02-21 17:36:45 -0500 |
commit | 2fbe967b3eb7466f679307b38564b8271c093241 (patch) | |
tree | d5e97862217a0a89e538f073c7b66483438c2cca | |
parent | 962033d55d0761e0716a01a715c6659c8c8dfc41 (diff) |
XArray: Fix xa_erase of 2-byte aligned entries
xas_store() was interpreting the entry it found in the array as a node
entry if the bottom two bits had value 2. That's only true if either
the entry is in the root node or in a non-leaf node.
Signed-off-by: Matthew Wilcox <willy@infradead.org>
-rw-r--r-- | lib/test_xarray.c | 16 | ||||
-rw-r--r-- | lib/xarray.c | 2 |
2 files changed, 16 insertions, 2 deletions
diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 52f8ecff8c0c..bc202d468a6b 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c | |||
@@ -1355,6 +1355,20 @@ static void check_align_1(struct xarray *xa, char *name) | |||
1355 | xa_destroy(xa); | 1355 | xa_destroy(xa); |
1356 | } | 1356 | } |
1357 | 1357 | ||
1358 | static void check_align_2(struct xarray *xa, char *name) | ||
1359 | { | ||
1360 | int i; | ||
1361 | |||
1362 | XA_BUG_ON(xa, !xa_empty(xa)); | ||
1363 | |||
1364 | for (i = 0; i < 8; i++) { | ||
1365 | XA_BUG_ON(xa, xa_store(xa, 0, name + i, GFP_KERNEL) != NULL); | ||
1366 | xa_erase(xa, 0); | ||
1367 | } | ||
1368 | |||
1369 | XA_BUG_ON(xa, !xa_empty(xa)); | ||
1370 | } | ||
1371 | |||
1358 | static noinline void check_align(struct xarray *xa) | 1372 | static noinline void check_align(struct xarray *xa) |
1359 | { | 1373 | { |
1360 | char name[] = "Motorola 68000"; | 1374 | char name[] = "Motorola 68000"; |
@@ -1363,7 +1377,7 @@ static noinline void check_align(struct xarray *xa) | |||
1363 | check_align_1(xa, name + 1); | 1377 | check_align_1(xa, name + 1); |
1364 | check_align_1(xa, name + 2); | 1378 | check_align_1(xa, name + 2); |
1365 | check_align_1(xa, name + 3); | 1379 | check_align_1(xa, name + 3); |
1366 | // check_align_2(xa, name); | 1380 | check_align_2(xa, name); |
1367 | } | 1381 | } |
1368 | 1382 | ||
1369 | static LIST_HEAD(shadow_nodes); | 1383 | static LIST_HEAD(shadow_nodes); |
diff --git a/lib/xarray.c b/lib/xarray.c index 3f10198f00b7..2cc3798672f7 100644 --- a/lib/xarray.c +++ b/lib/xarray.c | |||
@@ -800,7 +800,7 @@ void *xas_store(struct xa_state *xas, void *entry) | |||
800 | * entry is set to NULL. | 800 | * entry is set to NULL. |
801 | */ | 801 | */ |
802 | rcu_assign_pointer(*slot, entry); | 802 | rcu_assign_pointer(*slot, entry); |
803 | if (xa_is_node(next)) | 803 | if (xa_is_node(next) && (!node || node->shift)) |
804 | xas_free_nodes(xas, xa_to_node(next)); | 804 | xas_free_nodes(xas, xa_to_node(next)); |
805 | if (!node) | 805 | if (!node) |
806 | break; | 806 | break; |