xref: /openbmc/linux/net/ceph/string_table.c (revision b2441318)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
251e92737SYan, Zheng #include <linux/slab.h>
351e92737SYan, Zheng #include <linux/gfp.h>
451e92737SYan, Zheng #include <linux/string.h>
551e92737SYan, Zheng #include <linux/spinlock.h>
651e92737SYan, Zheng #include <linux/ceph/string_table.h>
751e92737SYan, Zheng 
851e92737SYan, Zheng static DEFINE_SPINLOCK(string_tree_lock);
951e92737SYan, Zheng static struct rb_root string_tree = RB_ROOT;
1051e92737SYan, Zheng 
ceph_find_or_create_string(const char * str,size_t len)1151e92737SYan, Zheng struct ceph_string *ceph_find_or_create_string(const char* str, size_t len)
1251e92737SYan, Zheng {
1351e92737SYan, Zheng 	struct ceph_string *cs, *exist;
1451e92737SYan, Zheng 	struct rb_node **p, *parent;
1551e92737SYan, Zheng 	int ret;
1651e92737SYan, Zheng 
1751e92737SYan, Zheng 	exist = NULL;
1851e92737SYan, Zheng 	spin_lock(&string_tree_lock);
1951e92737SYan, Zheng 	p = &string_tree.rb_node;
2051e92737SYan, Zheng 	while (*p) {
2151e92737SYan, Zheng 		exist = rb_entry(*p, struct ceph_string, node);
2251e92737SYan, Zheng 		ret = ceph_compare_string(exist, str, len);
2351e92737SYan, Zheng 		if (ret > 0)
2451e92737SYan, Zheng 			p = &(*p)->rb_left;
2551e92737SYan, Zheng 		else if (ret < 0)
2651e92737SYan, Zheng 			p = &(*p)->rb_right;
2751e92737SYan, Zheng 		else
2851e92737SYan, Zheng 			break;
2951e92737SYan, Zheng 		exist = NULL;
3051e92737SYan, Zheng 	}
3151e92737SYan, Zheng 	if (exist && !kref_get_unless_zero(&exist->kref)) {
3251e92737SYan, Zheng 		rb_erase(&exist->node, &string_tree);
3351e92737SYan, Zheng 		RB_CLEAR_NODE(&exist->node);
3451e92737SYan, Zheng 		exist = NULL;
3551e92737SYan, Zheng 	}
3651e92737SYan, Zheng 	spin_unlock(&string_tree_lock);
3751e92737SYan, Zheng 	if (exist)
3851e92737SYan, Zheng 		return exist;
3951e92737SYan, Zheng 
4051e92737SYan, Zheng 	cs = kmalloc(sizeof(*cs) + len + 1, GFP_NOFS);
4151e92737SYan, Zheng 	if (!cs)
4251e92737SYan, Zheng 		return NULL;
4351e92737SYan, Zheng 
4451e92737SYan, Zheng 	kref_init(&cs->kref);
4551e92737SYan, Zheng 	cs->len = len;
4651e92737SYan, Zheng 	memcpy(cs->str, str, len);
4751e92737SYan, Zheng 	cs->str[len] = 0;
4851e92737SYan, Zheng 
4951e92737SYan, Zheng retry:
5051e92737SYan, Zheng 	exist = NULL;
5151e92737SYan, Zheng 	parent = NULL;
5251e92737SYan, Zheng 	p = &string_tree.rb_node;
5351e92737SYan, Zheng 	spin_lock(&string_tree_lock);
5451e92737SYan, Zheng 	while (*p) {
5551e92737SYan, Zheng 		parent = *p;
5651e92737SYan, Zheng 		exist = rb_entry(*p, struct ceph_string, node);
5751e92737SYan, Zheng 		ret = ceph_compare_string(exist, str, len);
5851e92737SYan, Zheng 		if (ret > 0)
5951e92737SYan, Zheng 			p = &(*p)->rb_left;
6051e92737SYan, Zheng 		else if (ret < 0)
6151e92737SYan, Zheng 			p = &(*p)->rb_right;
6251e92737SYan, Zheng 		else
6351e92737SYan, Zheng 			break;
6451e92737SYan, Zheng 		exist = NULL;
6551e92737SYan, Zheng 	}
6651e92737SYan, Zheng 	ret = 0;
6751e92737SYan, Zheng 	if (!exist) {
6851e92737SYan, Zheng 		rb_link_node(&cs->node, parent, p);
6951e92737SYan, Zheng 		rb_insert_color(&cs->node, &string_tree);
7051e92737SYan, Zheng 	} else if (!kref_get_unless_zero(&exist->kref)) {
7151e92737SYan, Zheng 		rb_erase(&exist->node, &string_tree);
7251e92737SYan, Zheng 		RB_CLEAR_NODE(&exist->node);
7351e92737SYan, Zheng 		ret = -EAGAIN;
7451e92737SYan, Zheng 	}
7551e92737SYan, Zheng 	spin_unlock(&string_tree_lock);
7651e92737SYan, Zheng 	if (ret == -EAGAIN)
7751e92737SYan, Zheng 		goto retry;
7851e92737SYan, Zheng 
7951e92737SYan, Zheng 	if (exist) {
8051e92737SYan, Zheng 		kfree(cs);
8151e92737SYan, Zheng 		cs = exist;
8251e92737SYan, Zheng 	}
8351e92737SYan, Zheng 
8451e92737SYan, Zheng 	return cs;
8551e92737SYan, Zheng }
8651e92737SYan, Zheng EXPORT_SYMBOL(ceph_find_or_create_string);
8751e92737SYan, Zheng 
ceph_release_string(struct kref * ref)8851e92737SYan, Zheng void ceph_release_string(struct kref *ref)
8951e92737SYan, Zheng {
9051e92737SYan, Zheng 	struct ceph_string *cs = container_of(ref, struct ceph_string, kref);
9151e92737SYan, Zheng 
9251e92737SYan, Zheng 	spin_lock(&string_tree_lock);
9351e92737SYan, Zheng 	if (!RB_EMPTY_NODE(&cs->node)) {
9451e92737SYan, Zheng 		rb_erase(&cs->node, &string_tree);
9551e92737SYan, Zheng 		RB_CLEAR_NODE(&cs->node);
9651e92737SYan, Zheng 	}
9751e92737SYan, Zheng 	spin_unlock(&string_tree_lock);
9851e92737SYan, Zheng 
99864364a2SWei Yongjun 	kfree_rcu(cs, rcu);
10051e92737SYan, Zheng }
10151e92737SYan, Zheng EXPORT_SYMBOL(ceph_release_string);
10251e92737SYan, Zheng 
ceph_strings_empty(void)10351e92737SYan, Zheng bool ceph_strings_empty(void)
10451e92737SYan, Zheng {
10551e92737SYan, Zheng 	return RB_EMPTY_ROOT(&string_tree);
10651e92737SYan, Zheng }
107