@@ -15,6 +15,8 @@
#include <linux/hash.h>
#include <linux/hashtable.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
/*
size of one hash tree struct: [16]Bytes
@@ -112,6 +114,17 @@ enum ht_flags { /* htf: htree working flags (keep order) */
htf_freed,
};
+struct htree_root { /* root: hash tree root */
+ spinlock_t ht_lock; /* lock while update */
+ struct hash_tree __rcu *ht_first; /* start of the hash tree */
+};
+
+#define DEFINE_HTREE_ROOT(name) \
+ struct htree_root name = { \
+ .ht_lock = __SPIN_LOCK_UNLOCKED(name.ht_lock), \
+ .ht_first = NULL, \
+ }
+
#define HTREE_BITS_START 8 /* start of hash bits(default) */
#define HTREE_BITS_END 3 /* end of hash bits */
#define HTREE_BITS_SHIFT 3 /* shift of hash bits */
@@ -235,7 +248,7 @@ struct htree_data *ht_insert(struct htree_state *hts, struct hash_tree *htree,
struct htree_data *ht_erase(struct htree_state *hts,
struct hash_tree *htree, u64 index);
-enum ht_flags ht_destroy(struct htree_state *hts, struct hash_tree *htree);
+enum ht_flags ht_destroy_lock(struct htree_state *hts, struct htree_root *root);
void ht_statis(struct htree_state *hts, struct hash_tree *htree,
s32 *acnt, u64 *dcnt);
@@ -243,5 +256,107 @@ void ht_statis(struct htree_state *hts, struct hash_tree *htree,
struct htree_data *ht_most_index(struct htree_state *hts,
struct hash_tree *htree);
+/* spin_lock API */
+#define ht_trylock(xa) spin_trylock(&(xa)->ht_lock)
+#define ht_lock(xa) spin_lock(&(xa)->ht_lock)
+#define ht_unlock(xa) spin_unlock(&(xa)->ht_lock)
+#define ht_lock_bh(xa) spin_lock_bh(&(xa)->ht_lock)
+#define ht_unlock_bh(xa) spin_unlock_bh(&(xa)->ht_lock)
+#define ht_lock_irq(xa) spin_lock_irq(&(xa)->ht_lock)
+#define ht_unlock_irq(xa) spin_unlock_irq(&(xa)->ht_lock)
+#define ht_lock_irqsave(xa, flags) \
+ spin_lock_irqsave(&(xa)->ht_lock, flags)
+#define ht_unlock_irqrestore(xa, flags) \
+ spin_unlock_irqrestore(&(xa)->ht_lock, flags)
+#define ht_lock_nested(xa, subclass) \
+ spin_lock_nested(&(xa)->ht_lock, subclass)
+#define ht_lock_bh_nested(xa, subclass) \
+ spin_lock_bh_nested(&(xa)->ht_lock, subclass)
+#define ht_lock_irq_nested(xa, subclass) \
+ spin_lock_irq_nested(&(xa)->ht_lock, subclass)
+#define ht_lock_irqsave_nested(xa, flags, subclass) \
+ spin_lock_irqsave_nested(&(xa)->ht_lock, flags, subclass)
+
+
+static inline void htree_root_alloc(struct htree_state *hts,
+ struct htree_root *root)
+{
+ rcu_assign_pointer(root->ht_first, ht_table_alloc(hts));
+}
+
+static inline struct hash_tree *htree_first_rcu(const struct htree_root *root)
+{
+ return rcu_dereference_check(root->ht_first,
+ lockdep_is_held(&root->ht_lock));
+}
+
+static inline struct hash_tree *htree_first_rcu_locked(const struct htree_root *root)
+{
+ return rcu_dereference_protected(root->ht_first,
+ lockdep_is_held(&root->ht_lock));
+}
+
+
+static inline __must_check struct htree_data *ht_insert_lock(
+ struct htree_state *hts, struct htree_root *root,
+ struct htree_data *hdata, enum ht_flags req)
+{
+ ht_lock(root);
+ hdata = ht_insert(hts, htree_first_rcu_locked(root), hdata, req);
+ ht_unlock(root);
+ return hdata;
+}
+
+static inline __must_check struct htree_data *ht_insert_lock_irq(
+ struct htree_state *hts, struct htree_root *root,
+ struct htree_data *hdata, enum ht_flags req)
+{
+ ht_lock_irq(root);
+ hdata = ht_insert(hts, htree_first_rcu_locked(root), hdata, req);
+ ht_unlock_irq(root);
+ return hdata;
+}
+
+static inline __must_check struct htree_data *ht_insert_lock_irqsave(
+ struct htree_state *hts, struct htree_root *root,
+ struct htree_data *hdata, enum ht_flags req)
+{
+ unsigned long flags;
+ ht_lock_irqsave(root, flags);
+ hdata = ht_insert(hts, htree_first_rcu_locked(root), hdata, req);
+ ht_unlock_irqrestore(root, flags);
+ return hdata;
+}
+
+static inline __must_check struct htree_data *ht_erase_lock(
+ struct htree_state *hts, struct htree_root *root, u64 index)
+{
+ struct htree_data *hdata;
+ ht_lock(root);
+ hdata = ht_erase(hts, htree_first_rcu_locked(root), index);
+ ht_unlock(root);
+ return hdata;
+}
+
+static inline __must_check struct htree_data *ht_erase_lock_irq(
+ struct htree_state *hts, struct htree_root *root, u64 index)
+{
+ struct htree_data *hdata;
+ ht_lock_irq(root);
+ hdata = ht_erase(hts, htree_first_rcu_locked(root), index);
+ ht_unlock_irq(root);
+ return hdata;
+}
+
+static inline __must_check struct htree_data *ht_erase_lock_irqsave(
+ struct htree_state *hts, struct htree_root *root, u64 index)
+{
+ unsigned long flags;
+ struct htree_data *hdata;
+ ht_lock_irqsave(root, flags);
+ hdata = ht_erase(hts, htree_first_rcu_locked(root), index);
+ ht_unlock_irqrestore(root, flags);
+ return hdata;
+}
#endif /* _LINUX_HTREE_H */
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * htree/htree-api.c
+ * htree/htree-test.c
* Hash-Trees test codes to verify
*
* Copyright(C) 2024, JaeJoon Jung <rgbi3307@gmail.com>
@@ -17,28 +17,30 @@
Hash Tree API flow
------------------
- *hts = ht_hts_alloc() //alloc hts
- ht_hts_clear_init(hts, ...)
+ DEFINE_HTREE_ROOT(ht_root); //define htree_root
- *htree = ht_table_alloc(hts) //alloc first(depth:0) htree
+ *hts = ht_hts_alloc(); //alloc hts
+ ht_hts_clear_init(hts, ...);
+
+ htree_root_alloc(hts, &ht_root); //alloc first hash tree
run_loop() {
- *udata = _data_alloc(index) //alloc udata
+ *udata = _data_alloc(index); //alloc udata
- ht_insert(hts, htree, udata->hdata, ..)
- ht_erase(hts, htree, index)
- hdata = ht_find(hts, htree, index)
- hdata = ht_most_index(hts, htree)
+ ht_insert_lock(hts, &ht_root, udata->hdata, ..);
+ ht_erase_lock(hts, &ht_root, index);
+ hdata = ht_find(hts, ht_root.ht_first, index);
+ hdata = ht_most_index(hts, ht_root.ht_first);
- ht_statis(hts, htree, ...)
+ ht_statis(hts, ht_root.ht_first, ...);
}
- htree_erase_all(hts, htree) //remove all udata
+ htree_erase_all_lock(hts, &ht_root) //remove all udata
- ht_destroy(hts, htree) //remove all htree
+ ht_destroy_lock(hts, &ht_root) //remove all htree
- kfree(hts) //remove hts
+ kfree(hts) //remove hts
*/
@@ -75,6 +77,8 @@
#define HTREE_TEST_SCHED_CNT 200
+DEFINE_HTREE_ROOT(ht_root);
+
struct data_struct {
/* user defined data members ... */
char a;
@@ -361,19 +365,19 @@ static void __htree_debug_walks_all(struct htree_state *hts,
/**
* htree_walks_all_debug - display to debug all indexes
* @hts: htree_state pointer
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
* @index: index to find
*
* this function cycles through all hash tables and outputs all indexes.
*/
static void htree_debug_walks_all(struct htree_state *hts,
- struct hash_tree *htree, u64 index)
+ struct htree_root *root, u64 index)
{
pr_ht_debug("[@@@@) walking: sbit:%u, dmax:%u, acnt:%d, dcnt:%llu\n\n",
hts->sbit, hts->dmax, hts->acnt, hts->dcnt);
hts->dept = 0;
- __htree_debug_walks_all(hts, htree, index);
+ __htree_debug_walks_all(hts, htree_first_rcu(root), index);
pr_ht_debug("(@@@@] done: sbit:%u, dmax:%u, acnt:%d, dcnt:%llu\n\n",
hts->sbit, hts->dmax, hts->acnt, hts->dcnt);
@@ -381,14 +385,14 @@ static void htree_debug_walks_all(struct htree_state *hts,
#endif /* HTREE_DEBUG_DETAIL */
/**
- * __htree_erase_all - erase udata all
+ * __htree_erase_all_lock - erase udata all
* @hts: htree_state pointer
* @htree: hash_tree root pointer
* @erased: erased udata count
*
* this function cycles through all hash tables and erase udata all
*/
-static void __htree_erase_all(struct htree_state *hts,
+static void __htree_erase_all_lock(struct htree_state *hts,
struct hash_tree *htree, u64 *erased)
{
u8 bits, ncnt;
@@ -421,7 +425,7 @@ static void __htree_erase_all(struct htree_state *hts,
hts->dept++;
pnum = anum;
/* recursive call */
- __htree_erase_all(hts, _next, erased);
+ __htree_erase_all_lock(hts, _next, erased);
anum = pnum;
hts->dept--;
} else {
@@ -431,13 +435,13 @@ static void __htree_erase_all(struct htree_state *hts,
}
/**
- * htree_erase_all - erase udata all
+ * htree_erase_all_lock - erase udata all
* @hts: htree_state pointer
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
*
* return: erased all udata count
*/
-static u64 htree_erase_all(struct htree_state *hts, struct hash_tree *htree)
+static u64 htree_erase_all_lock(struct htree_state *hts, struct htree_root *root)
{
u64 erased = 0;
@@ -445,7 +449,10 @@ static u64 htree_erase_all(struct htree_state *hts, struct hash_tree *htree)
hts->sbit, hts->dmax, hts->acnt, hts->dcnt);
hts->dept = 0;
- __htree_erase_all(hts, htree, &erased);
+
+ ht_lock(root);
+ __htree_erase_all_lock(hts, htree_first_rcu_locked(root), &erased);
+ ht_unlock(root);
pr_ht_info("(~~~~] done: sbit:%u, acnt:%d, dcnt:%llu, erased:%llu\n\n",
hts->sbit, hts->acnt, hts->dcnt, erased);
@@ -456,7 +463,7 @@ static u64 htree_erase_all(struct htree_state *hts, struct hash_tree *htree)
/**
* _htree_insert_range - insert udata to hash tree using ht_insert()
* @hts: htree_state pointer
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
* @start: start index to insert
* @end: end index to insert
* @gap: gap between indices
@@ -466,7 +473,7 @@ static u64 htree_erase_all(struct htree_state *hts, struct hash_tree *htree)
* if req is htf_ins, the new udata is inserted next to each other.
* if req is htf_erase, the new udata is inserted, and old udata is erased.
*/
-static u64 _htree_insert_range(struct htree_state *hts, struct hash_tree *htree,
+static u64 _htree_insert_range(struct htree_state *hts, struct htree_root *root,
u64 start, u64 end, u64 gap, enum ht_flags req)
{
u64 index;
@@ -478,7 +485,7 @@ static u64 _htree_insert_range(struct htree_state *hts, struct hash_tree *htree,
start, end, gap);
for (index = start; index <= end; index += gap) {
udata = _htree_data_alloc(index);
- rdata = ht_insert(hts, htree, &udata->hdata, req);
+ rdata = ht_insert_lock(hts, root, &udata->hdata, req);
if (req == htf_erase && rdata) {
udata = hlist_entry_safe(rdata, struct data_struct, hdata);
if (udata && rdata->index == index) {
@@ -500,12 +507,12 @@ static u64 _htree_insert_range(struct htree_state *hts, struct hash_tree *htree,
/**
* _htree_find_range - find udata in the hash tree using ht_find()
* @hts: htree_state pointer
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
* @start: start index to find
* @end: end index to find
* @gap: gap between indices
*/
-static u64 _htree_find_range(struct htree_state *hts, struct hash_tree *htree,
+static u64 _htree_find_range(struct htree_state *hts, struct htree_root *root,
u64 start, u64 end, u64 gap)
{
u64 index;
@@ -516,7 +523,7 @@ static u64 _htree_find_range(struct htree_state *hts, struct hash_tree *htree,
pr_ht_info("[****) finding: [s:%llu ... e:%llu] (g:%llu)\n",
start, end, gap);
for (index = start; index <= end; index += gap) {
- rdata = ht_find(hts, htree, index);
+ rdata = ht_find(hts, htree_first_rcu(root), index);
if (rdata) {
udata = hlist_entry_safe(rdata, struct data_struct, hdata);
if (udata && rdata->index == index) {
@@ -525,6 +532,7 @@ static u64 _htree_find_range(struct htree_state *hts, struct hash_tree *htree,
found++;
}
}
+
loop++;
if (!(loop % HTREE_TEST_SCHED_CNT))
schedule();
@@ -537,23 +545,25 @@ static u64 _htree_find_range(struct htree_state *hts, struct hash_tree *htree,
/**
* _htree_erase_range - erase udata from hash tree using ht_erase()
* @hts: htree_state pointer
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
* @start: start index to erase
* @end: end index to erase
* @gap: gap between indices
*/
-static u64 _htree_erase_range(struct htree_state *hts, struct hash_tree *htree,
+static u64 _htree_erase_range(struct htree_state *hts, struct htree_root *root,
u64 start, u64 end, u64 gap)
{
u64 index;
u64 loop = 0, erased = 0;
+ struct hash_tree *htree;
struct data_struct *udata;
struct htree_data *rdata;
pr_ht_info("[----) erasing: [s:%llu ... e:%llu] (g:%llu)\n",
start, end, gap);
for (index = start; index <= end; index += gap) {
- rdata = ht_erase(hts, htree, index);
+ htree = htree_first_rcu(root);
+ rdata = ht_erase_lock(hts, root, index);
if (rdata) {
udata = hlist_entry_safe(rdata, struct data_struct, hdata);
if (udata && rdata->index == index) {
@@ -580,22 +590,24 @@ static u64 _htree_erase_range(struct htree_state *hts, struct hash_tree *htree,
/**
* _htree_update_range - update udata in the hash tree using ft_find()
* @hts: htree_state pointer
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
* @start: start index to update
* @end: end index to update
* @gap: gap between indices
*/
-static u64 _htree_update_range(struct htree_state *hts, struct hash_tree *htree,
+static u64 _htree_update_range(struct htree_state *hts, struct htree_root *root,
u64 start, u64 end, u64 gap)
{
u64 index;
u64 loop = 0, updated = 0;
+ struct hash_tree *htree;
struct data_struct *udata;
struct htree_data *rdata;
pr_ht_info("[####) updating: [s:%llu ... e:%llu] (g:%llu)\n",
start, end, gap);
for (index = start; index <= end; index += gap) {
+ htree = htree_first_rcu(root);
rdata = ht_find(hts, htree, index);
if (rdata) {
udata = hlist_entry_safe(rdata, struct data_struct, hdata);
@@ -630,14 +642,14 @@ static u64 _htree_update_range(struct htree_state *hts, struct hash_tree *htree,
/**
* _htree_statis - calculate hash tree statistics and get into hts.
* @hts: htree_state pointer to store statistics
- * @htree: hash_tree root pointer
+ * @root: hash_tree root pointer
*/
-static void _htree_statis(struct htree_state *hts, struct hash_tree *htree)
+static void _htree_statis(struct htree_state *hts, struct htree_root *root)
{
s32 acnt = 0;
u64 dcnt = 0;
- ht_statis(hts, htree, &acnt, &dcnt);
+ ht_statis(hts, htree_first_rcu(root), &acnt, &dcnt);
if (hts->dcnt == dcnt && hts->acnt == acnt) {
pr_ht_info("[ OK ] statist: acnt:%d, dcnt:%llu ", acnt, dcnt);
@@ -651,8 +663,10 @@ static void _htree_statis(struct htree_state *hts, struct hash_tree *htree)
/**
* _htree_statis_info - shows information calculated by htree_statis().
+ * @hts: htree_state pointer to read statistics
+ * @root: hash_tree root pointer
*/
-static void _htree_statis_info(struct htree_state *hts, struct hash_tree *htree)
+static void _htree_statis_info(struct htree_state *hts, struct htree_root *root)
{
u32 sizh = sizeof(struct hash_tree);
u32 sizd = sizeof(struct data_struct);
@@ -663,7 +677,7 @@ static void _htree_statis_info(struct htree_state *hts, struct hash_tree *htree)
u64 smem = hsum + dsum;
if (hts->asum == 0)
- _htree_statis(hts, htree);
+ _htree_statis(hts, root);
pr_ht_stat("------------------------------------------\n");
pr_ht_stat(" hash start bits(sbit) : %10d\n", hts->sbit);
@@ -692,10 +706,11 @@ static void _htree_statis_info(struct htree_state *hts, struct hash_tree *htree)
* if sort flag is HTREE_FLAG_ASCD, root hash table has the smallest index.
* if sort flag is HTREE_FLAG_DECD, root hash table has the largest index.
*/
-static void _htree_get_most_index(struct htree_state *hts, struct hash_tree *htree)
+static void _htree_get_most_index(struct htree_state *hts, struct htree_root *root)
{
struct htree_data *hdata;
- hdata = ht_most_index(hts, htree);
+
+ hdata = ht_most_index(hts, htree_first_rcu(root));
if (hdata) {
if (hts->sort == HTREE_FLAG_ASCD) {
pr_ht_stat("[MOST] smallest index:%llu\n\n", hdata->index);
@@ -708,20 +723,20 @@ static void _htree_get_most_index(struct htree_state *hts, struct hash_tree *htr
/**
* _htree_remove_all - remove all udata and hash trees
*
- * before run ht_destroy(), the udata must be erased all.
- * ht_destroy() removes all hash trees, but it does not remove the udata.
+ * before run ht_destroy_lock(), the udata must be erased all.
+ * ht_destroy_lock() removes all hash trees, but it does not remove the udata.
*/
-static void _htree_remove_all(struct htree_state *hts, struct hash_tree *htree)
+static void _htree_remove_all(struct htree_state *hts, struct htree_root *root)
{
/* remove all udata */
- hts->dcnt -= htree_erase_all(hts, htree);
+ hts->dcnt -= htree_erase_all_lock(hts, root);
if (hts->dcnt != 0) {
pr_ht_warn("[WARN] erase remained acnt:%d, dcnt:%llu\n\n",
hts->acnt, hts->dcnt);
}
/* remove all hash trees */
- if (ht_destroy(hts, htree) == htf_ok) {
+ if (ht_destroy_lock(hts, root) == htf_ok) {
pr_ht_stat("[ OK ] destroy remained acnt:%d, dcnt:%llu\n\n",
hts->acnt, hts->dcnt);
} else {
@@ -743,7 +758,6 @@ static void _htree_remove_all(struct htree_state *hts, struct hash_tree *htree)
*/
static u64 _htree_test_index_loop(struct htree_state *hts, u64 start, u64 end)
{
- struct hash_tree *htree;
u64 inserted, found, erased, updated;
u64 dcnt, slice;
@@ -752,42 +766,42 @@ static u64 _htree_test_index_loop(struct htree_state *hts, u64 start, u64 end)
slice = (end - start) / 10 + 2;
/* first root hash tree alloc */
- htree = ht_table_alloc(hts);
+ htree_root_alloc(hts, &ht_root);
- inserted = _htree_insert_range(hts, htree, start, end, 1, htf_ins);
+ inserted = _htree_insert_range(hts, &ht_root, start, end, 1, htf_ins);
if (inserted != hts->dcnt) {
pr_ht_err("[FAIL] inserted:%llu, dcnt:%llu, diff:%lld\n\n",
inserted, hts->dcnt, inserted - hts->dcnt);
}
- _htree_statis(hts, htree);
+ _htree_statis(hts, &ht_root);
- erased = _htree_erase_range(hts, htree, start, end, slice);
- found = _htree_find_range(hts, htree, start, end, slice);
+ erased = _htree_erase_range(hts, &ht_root, start, end, slice);
+ found = _htree_find_range(hts, &ht_root, start, end, slice);
if (found) {
pr_ht_err("[FAIL] erased:%llu, found:%llu, diff:%lld\n\n",
erased, found, erased - found);
}
- _htree_statis(hts, htree);
+ _htree_statis(hts, &ht_root);
- inserted = _htree_insert_range(hts, htree, start, end, slice, htf_ins);
- updated = _htree_update_range(hts, htree, start, end, slice);
+ inserted = _htree_insert_range(hts, &ht_root, start, end, slice, htf_ins);
+ updated = _htree_update_range(hts, &ht_root, start, end, slice);
if (inserted != updated) {
pr_ht_err("[FAIL] inserted:%llu, updated:%llu, diff:%lld\n\n",
inserted, updated, inserted - updated);
}
- _htree_statis(hts, htree);
- _htree_get_most_index(hts, htree);
+ _htree_statis(hts, &ht_root);
+ _htree_get_most_index(hts, &ht_root);
#ifdef HTREE_DEBUG_DETAIL
- htree_debug_walks_all(hts, htree, 0);
+ htree_debug_walks_all(hts, &ht_root, 0);
#endif
- _htree_statis_info(hts, htree);
+ _htree_statis_info(hts, &ht_root);
dcnt = hts->dcnt;
- _htree_remove_all(hts, htree);
+ _htree_remove_all(hts, &ht_root);
return dcnt;
}
@@ -872,7 +886,6 @@ index type:<%s>, sorting type:<%s>\n", idxts[idx_type], sorts[sort_type]);
static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
{
u64 i, index;
- struct hash_tree *htree;
struct data_struct *udata;
struct htree_data *rdata;
u64 loop = 0, inserted = 0, erased = 0;
@@ -886,13 +899,13 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
ht_hts_clear_init(hts, maxnr, idx_type, sort_type);
/* first root hash tree alloc */
- htree = ht_table_alloc(hts);
+ htree_root_alloc(hts, &ht_root);
pr_ht_stat("[START) RANDOM: sbit:%u, index type:<%s>, sorting type:<%s>\n\n",
hts->sbit, idxts[idx_type], sorts[sort_type]);
udata = _htree_data_alloc(check_idx);
- rdata = ht_insert(hts, htree, &udata->hdata, htf_ins);
+ rdata = ht_insert_lock(hts, &ht_root, &udata->hdata, htf_ins);
inserted++;
loop++;
@@ -902,7 +915,7 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
get_random_u32() : get_random_u64();
udata = _htree_data_alloc(index);
- rdata = ht_insert(hts, htree, &udata->hdata, htf_ins);
+ rdata = ht_insert_lock(hts, &ht_root, &udata->hdata, htf_ins);
if (!rdata)
inserted++;
loop++;
@@ -910,9 +923,9 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
schedule();
}
- _htree_statis(hts, htree);
+ _htree_statis(hts, &ht_root);
- rdata = ht_find(hts, htree, check_idx);
+ rdata = ht_find(hts, htree_first_rcu(&ht_root), check_idx);
if (!rdata) {
pr_ht_err("[FAIL] NOT found check index:%llu\n\n", check_idx);
}
@@ -923,7 +936,7 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
index = (idx_type == HTREE_FLAG_IDX32) ?
get_random_u32() : get_random_u64();
- rdata = ht_erase(hts, htree, index);
+ rdata = ht_erase_lock(hts, &ht_root, index);
if (rdata) {
udata = hlist_entry_safe(rdata, struct data_struct, hdata);
if (udata && rdata->index == index) {
@@ -938,9 +951,9 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
schedule();
}
- _htree_statis(hts, htree);
+ _htree_statis(hts, &ht_root);
- rdata = ht_find(hts, htree, check_idx);
+ rdata = ht_find(hts, htree_first_rcu(&ht_root), check_idx);
if (!rdata) {
pr_ht_info("[INFO] check index:%llu (erased)\n\n", check_idx);
}
@@ -949,13 +962,13 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
loop, inserted, erased);
#ifdef HTREE_DEBUG_DETAIL
- htree_debug_walks_all(hts, htree, 0);
+ htree_debug_walks_all(hts, &ht_root, 0);
#endif
- _htree_get_most_index(hts, htree);
- _htree_statis_info(hts, htree);
+ _htree_get_most_index(hts, &ht_root);
+ _htree_statis_info(hts, &ht_root);
- _htree_remove_all(hts, htree);
+ _htree_remove_all(hts, &ht_root);
kfree(hts);
}
@@ -975,7 +988,6 @@ static void _htree_test_idx_random(u8 idx_type, u8 sort_type, u64 maxnr)
*/
static void _htree_test_index_same(u8 idx_type, u8 sort_type, u64 maxnr)
{
- struct hash_tree *htree;
u64 inserted, found;
const char *idxts[] = { "64bits", "32bits" };
const char *sorts[] = { "ASCD", "DECD" };
@@ -987,49 +999,49 @@ static void _htree_test_index_same(u8 idx_type, u8 sort_type, u64 maxnr)
ht_hts_clear_init(hts, maxnr, idx_type, sort_type);
/* first root hash tree alloc */
- htree = ht_table_alloc(hts);
+ htree_root_alloc(hts, &ht_root);
pr_ht_stat("[START) SAME: sbit:%u, index type:<%s>, sorting type:<%s>\n\n",
hts->sbit, idxts[idx_type], sorts[sort_type]);
pr_ht_stat("[loop) %llu: new index inserting(htf_ins)\n\n", maxnr);
- inserted = _htree_insert_range(hts, htree, 0, maxnr, gap - 1, htf_ins);
+ inserted = _htree_insert_range(hts, &ht_root, 0, maxnr, gap - 1, htf_ins);
if (inserted != hts->dcnt) {
pr_ht_err("[FAIL] inserted:%llu, dcnt:%llu, diff:%lld\n\n",
inserted, hts->dcnt, inserted - hts->dcnt);
}
- _htree_statis(hts, htree);
+ _htree_statis(hts, &ht_root);
pr_ht_stat("[loop) %llu: SAME index inserting(htf_erase)\n\n", maxnr);
- inserted = _htree_insert_range(hts, htree, 1, maxnr, gap, htf_erase);
+ inserted = _htree_insert_range(hts, &ht_root, 1, maxnr, gap, htf_erase);
if (inserted != 0) {
pr_ht_err("[FAIL] inserted:%llu, dcnt:%llu, diff:%lld\n\n",
inserted, hts->dcnt, inserted - hts->dcnt);
}
pr_ht_stat("[loop) %llu: SAME index inserting(htf_ins)\n\n", maxnr);
- inserted = _htree_insert_range(hts, htree, 1, maxnr, gap, htf_ins);
+ inserted = _htree_insert_range(hts, &ht_root, 1, maxnr, gap, htf_ins);
if (inserted != (maxnr / gap)) {
pr_ht_err("[FAIL] inserted:%llu, dcnt:%llu, diff:%lld\n\n",
inserted, hts->dcnt, inserted - hts->dcnt);
}
- found = _htree_find_range(hts, htree, 0, maxnr, gap - 1);
+ found = _htree_find_range(hts, &ht_root, 0, maxnr, gap - 1);
if (found != (hts->dcnt - inserted)) {
pr_ht_err("[FAIL] dcnt:%llu, inserted:%llu, found:%llu\n\n",
hts->dcnt, inserted, found);
}
- _htree_statis(hts, htree);
+ _htree_statis(hts, &ht_root);
#ifdef HTREE_DEBUG_DETAIL
- htree_debug_walks_all(hts, htree, 0);
+ htree_debug_walks_all(hts, &ht_root, 0);
#endif
- _htree_get_most_index(hts, htree);
- _htree_statis_info(hts, htree);
+ _htree_get_most_index(hts, &ht_root);
+ _htree_statis_info(hts, &ht_root);
- _htree_remove_all(hts, htree);
+ _htree_remove_all(hts, &ht_root);
kfree(hts);
}
@@ -180,6 +180,9 @@ struct htree_data *ht_find(struct htree_state *hts,
struct htree_data *rdata = NULL;
struct hash_tree *rtree;
+ if (!htree)
+ return NULL;
+
if (_ht_find(hts, htree, index, &rdata, &rtree) == htf_find)
return rdata;
return NULL;
@@ -345,6 +348,9 @@ struct htree_data *ht_insert(struct htree_state *hts, struct hash_tree *htree,
struct hash_tree *rtree = NULL;
enum ht_flags htf;
+ if (!htree)
+ return NULL;
+
htf = _ht_find(hts, htree, hdata->index, &rdata, &rtree);
_ht_insert(hts, rtree, rdata, hdata, htf, req);
@@ -478,6 +484,9 @@ struct htree_data *ht_erase(struct htree_state *hts,
{
struct htree_data *rdata = NULL;
+ if (!htree)
+ return NULL;
+
if (_ht_erase(hts, htree, &rdata, index) == htf_erase)
return rdata;
@@ -533,22 +542,31 @@ static void __ht_free_all(struct htree_state *hts,
}
/**
- * ht_destroy - public function to free hash tree
+ * ht_destroy_lock - public function to free hash tree
* @hts: htree_state pointer
- * @htree: hash_tree pointer(root)
+ * @root: htree_tree pointer(root)
*
* this function removes all hash tree, but it does not remove udata.
*/
-enum ht_flags ht_destroy(struct htree_state *hts, struct hash_tree *htree)
+enum ht_flags ht_destroy_lock(struct htree_state *hts, struct htree_root *root)
{
s32 acnt = 0;
u64 dcnt = 0;
+ struct hash_tree *htree;
if (hts->acnt == 0 && hts->dcnt == 0)
return htf_ok;
+ htree = htree_first_rcu(root);
+ if (!htree)
+ return htf_none;
+
hts->dept = 0;
+
+ ht_lock(root);
__ht_free_all(hts, htree, &acnt, &dcnt);
+ RCU_INIT_POINTER(root->ht_first, NULL);
+ ht_unlock(root);
hts->acnt -= acnt;
hts->dcnt -= dcnt;
@@ -556,7 +574,7 @@ enum ht_flags ht_destroy(struct htree_state *hts, struct hash_tree *htree)
return (hts->dept == 0 && hts->dcnt == 0 && hts->acnt == 0) ?
htf_ok : htf_none;
}
-EXPORT_SYMBOL(ht_destroy);
+EXPORT_SYMBOL(ht_destroy_lock);
/**
* __ht_statis - private function to call recursively to calculate nodes
@@ -613,6 +631,9 @@ void ht_statis(struct htree_state *hts,
hts->dept = 0;
hts->dmax = 0;
+ if (!htree)
+ return;
+
__ht_statis(hts, htree, acnt, dcnt);
}
EXPORT_SYMBOL(ht_statis);
Implementation of new Hash Tree [PATCH v2] ------------------------------------------ Add spinlock.h and rcupdate.h in the include/linux/htree.h Add htree_root structue to interface locking. htree_root.ht_lock is spinlock_t to run spin_lock. htree_root.ht_first is __rcu type to access rcu API. Access the kernel standard API using macros. full source: ------------ https://github.com/kernel-bz/htree.git Manual(PDF): ------------ https://github.com/kernel-bz/htree/blob/main/docs/htree-20240802.pdf Signed-off-by: JaeJoon Jung <rgbi3307@gmail.com> --- include/linux/htree.h | 117 ++++++++++++++++++++++++++- lib/htree-test.c | 182 ++++++++++++++++++++++-------------------- lib/htree.c | 29 ++++++- 3 files changed, 238 insertions(+), 90 deletions(-)