.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Generic associative array implementation. |
---|
2 | 3 | * |
---|
3 | 4 | * See Documentation/core-api/assoc_array.rst for information. |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. |
---|
6 | 7 | * Written by David Howells (dhowells@redhat.com) |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public Licence |
---|
10 | | - * as published by the Free Software Foundation; either version |
---|
11 | | - * 2 of the Licence, or (at your option) any later version. |
---|
12 | 8 | */ |
---|
13 | 9 | //#define DEBUG |
---|
14 | 10 | #include <linux/rcupdate.h> |
---|
.. | .. |
---|
1117 | 1113 | index_key)) |
---|
1118 | 1114 | goto found_leaf; |
---|
1119 | 1115 | } |
---|
| 1116 | + /* fall through */ |
---|
1120 | 1117 | case assoc_array_walk_tree_empty: |
---|
1121 | 1118 | case assoc_array_walk_found_wrong_shortcut: |
---|
1122 | 1119 | default: |
---|
.. | .. |
---|
1465 | 1462 | struct assoc_array_ptr *cursor, *ptr; |
---|
1466 | 1463 | struct assoc_array_ptr *new_root, *new_parent, **new_ptr_pp; |
---|
1467 | 1464 | unsigned long nr_leaves_on_tree; |
---|
| 1465 | + bool retained; |
---|
1468 | 1466 | int keylen, slot, nr_free, next_slot, i; |
---|
1469 | 1467 | |
---|
1470 | 1468 | pr_devel("-->%s()\n", __func__); |
---|
.. | .. |
---|
1541 | 1539 | goto descend; |
---|
1542 | 1540 | } |
---|
1543 | 1541 | |
---|
| 1542 | +retry_compress: |
---|
1544 | 1543 | pr_devel("-- compress node %p --\n", new_n); |
---|
1545 | 1544 | |
---|
1546 | 1545 | /* Count up the number of empty slots in this node and work out the |
---|
.. | .. |
---|
1558 | 1557 | pr_devel("free=%d, leaves=%lu\n", nr_free, new_n->nr_leaves_on_branch); |
---|
1559 | 1558 | |
---|
1560 | 1559 | /* See what we can fold in */ |
---|
| 1560 | + retained = false; |
---|
1561 | 1561 | next_slot = 0; |
---|
1562 | 1562 | for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) { |
---|
1563 | 1563 | struct assoc_array_shortcut *s; |
---|
.. | .. |
---|
1607 | 1607 | pr_devel("[%d] retain node %lu/%d [nx %d]\n", |
---|
1608 | 1608 | slot, child->nr_leaves_on_branch, nr_free + 1, |
---|
1609 | 1609 | next_slot); |
---|
| 1610 | + retained = true; |
---|
1610 | 1611 | } |
---|
1611 | 1612 | } |
---|
1612 | 1613 | |
---|
| 1614 | + if (retained && new_n->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT) { |
---|
| 1615 | + pr_devel("internal nodes remain despite enough space, retrying\n"); |
---|
| 1616 | + goto retry_compress; |
---|
| 1617 | + } |
---|
1613 | 1618 | pr_devel("after: %lu\n", new_n->nr_leaves_on_branch); |
---|
1614 | 1619 | |
---|
1615 | 1620 | nr_leaves_on_tree = new_n->nr_leaves_on_branch; |
---|