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