| .. | .. |
|---|
| 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; |
|---|