aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2016-02-05 02:36:22 -0500
committerIlya Dryomov <idryomov@gmail.com>2016-07-27 20:55:37 -0400
commit51e9273796a57c08801f45580d3db3c51987a0cb (patch)
tree5eb35d4d7c0f44065b0fe17f0bb0a3c98202f215
parent7627151ea30bce2051e3cb27d7bb2c30083f86a5 (diff)
libceph: introduce reference counted string
The data structure is for storing namesapce string. It allows namespace string to be shared between cephfs inodes with same layout. This data structure can also be referenced by OSD request. Signed-off-by: Yan, Zheng <zyan@redhat.com>
-rw-r--r--include/linux/ceph/libceph.h1
-rw-r--r--include/linux/ceph/string_table.h62
-rw-r--r--net/ceph/Makefile2
-rw-r--r--net/ceph/ceph_common.c2
-rw-r--r--net/ceph/string_table.c111
5 files changed, 177 insertions, 1 deletions
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 690985daad1c..6afc5d98fad1 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -21,6 +21,7 @@
21#include <linux/ceph/mon_client.h> 21#include <linux/ceph/mon_client.h>
22#include <linux/ceph/osd_client.h> 22#include <linux/ceph/osd_client.h>
23#include <linux/ceph/ceph_fs.h> 23#include <linux/ceph/ceph_fs.h>
24#include <linux/ceph/string_table.h>
24 25
25/* 26/*
26 * mount options 27 * mount options
diff --git a/include/linux/ceph/string_table.h b/include/linux/ceph/string_table.h
new file mode 100644
index 000000000000..1b02c96daf75
--- /dev/null
+++ b/include/linux/ceph/string_table.h
@@ -0,0 +1,62 @@
1#ifndef _FS_CEPH_STRING_TABLE_H
2#define _FS_CEPH_STRING_TABLE_H
3
4#include <linux/types.h>
5#include <linux/kref.h>
6#include <linux/rbtree.h>
7#include <linux/rcupdate.h>
8
9struct ceph_string {
10 struct kref kref;
11 union {
12 struct rb_node node;
13 struct rcu_head rcu;
14 };
15 size_t len;
16 char str[];
17};
18
19extern void ceph_release_string(struct kref *ref);
20extern struct ceph_string *ceph_find_or_create_string(const char *str,
21 size_t len);
22extern bool ceph_strings_empty(void);
23
24static inline struct ceph_string *ceph_get_string(struct ceph_string *str)
25{
26 kref_get(&str->kref);
27 return str;
28}
29
30static inline void ceph_put_string(struct ceph_string *str)
31{
32 if (!str)
33 return;
34 kref_put(&str->kref, ceph_release_string);
35}
36
37static inline int ceph_compare_string(struct ceph_string *cs,
38 const char* str, size_t len)
39{
40 size_t cs_len = cs ? cs->len : 0;
41 if (cs_len != len)
42 return cs_len - len;
43 if (len == 0)
44 return 0;
45 return strncmp(cs->str, str, len);
46}
47
48#define ceph_try_get_string(x) \
49({ \
50 struct ceph_string *___str; \
51 rcu_read_lock(); \
52 for (;;) { \
53 ___str = rcu_dereference(x); \
54 if (!___str || \
55 kref_get_unless_zero(&___str->kref)) \
56 break; \
57 } \
58 rcu_read_unlock(); \
59 (___str); \
60})
61
62#endif
diff --git a/net/ceph/Makefile b/net/ceph/Makefile
index 958d9856912c..84cbed630c4b 100644
--- a/net/ceph/Makefile
+++ b/net/ceph/Makefile
@@ -11,5 +11,5 @@ libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
11 crypto.o armor.o \ 11 crypto.o armor.o \
12 auth_x.o \ 12 auth_x.o \
13 ceph_fs.o ceph_strings.o ceph_hash.o \ 13 ceph_fs.o ceph_strings.o ceph_hash.o \
14 pagevec.o snapshot.o 14 pagevec.o snapshot.o string_table.o
15 15
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 55d2bfee16d7..bddfcf6f09c2 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -747,6 +747,8 @@ out:
747static void __exit exit_ceph_lib(void) 747static void __exit exit_ceph_lib(void)
748{ 748{
749 dout("exit_ceph_lib\n"); 749 dout("exit_ceph_lib\n");
750 WARN_ON(!ceph_strings_empty());
751
750 ceph_osdc_cleanup(); 752 ceph_osdc_cleanup();
751 ceph_msgr_exit(); 753 ceph_msgr_exit();
752 ceph_crypto_shutdown(); 754 ceph_crypto_shutdown();
diff --git a/net/ceph/string_table.c b/net/ceph/string_table.c
new file mode 100644
index 000000000000..ca53c8319209
--- /dev/null
+++ b/net/ceph/string_table.c
@@ -0,0 +1,111 @@
1#include <linux/slab.h>
2#include <linux/gfp.h>
3#include <linux/string.h>
4#include <linux/spinlock.h>
5#include <linux/ceph/string_table.h>
6
7static DEFINE_SPINLOCK(string_tree_lock);
8static struct rb_root string_tree = RB_ROOT;
9
10struct ceph_string *ceph_find_or_create_string(const char* str, size_t len)
11{
12 struct ceph_string *cs, *exist;
13 struct rb_node **p, *parent;
14 int ret;
15
16 exist = NULL;
17 spin_lock(&string_tree_lock);
18 p = &string_tree.rb_node;
19 while (*p) {
20 exist = rb_entry(*p, struct ceph_string, node);
21 ret = ceph_compare_string(exist, str, len);
22 if (ret > 0)
23 p = &(*p)->rb_left;
24 else if (ret < 0)
25 p = &(*p)->rb_right;
26 else
27 break;
28 exist = NULL;
29 }
30 if (exist && !kref_get_unless_zero(&exist->kref)) {
31 rb_erase(&exist->node, &string_tree);
32 RB_CLEAR_NODE(&exist->node);
33 exist = NULL;
34 }
35 spin_unlock(&string_tree_lock);
36 if (exist)
37 return exist;
38
39 cs = kmalloc(sizeof(*cs) + len + 1, GFP_NOFS);
40 if (!cs)
41 return NULL;
42
43 kref_init(&cs->kref);
44 cs->len = len;
45 memcpy(cs->str, str, len);
46 cs->str[len] = 0;
47
48retry:
49 exist = NULL;
50 parent = NULL;
51 p = &string_tree.rb_node;
52 spin_lock(&string_tree_lock);
53 while (*p) {
54 parent = *p;
55 exist = rb_entry(*p, struct ceph_string, node);
56 ret = ceph_compare_string(exist, str, len);
57 if (ret > 0)
58 p = &(*p)->rb_left;
59 else if (ret < 0)
60 p = &(*p)->rb_right;
61 else
62 break;
63 exist = NULL;
64 }
65 ret = 0;
66 if (!exist) {
67 rb_link_node(&cs->node, parent, p);
68 rb_insert_color(&cs->node, &string_tree);
69 } else if (!kref_get_unless_zero(&exist->kref)) {
70 rb_erase(&exist->node, &string_tree);
71 RB_CLEAR_NODE(&exist->node);
72 ret = -EAGAIN;
73 }
74 spin_unlock(&string_tree_lock);
75 if (ret == -EAGAIN)
76 goto retry;
77
78 if (exist) {
79 kfree(cs);
80 cs = exist;
81 }
82
83 return cs;
84}
85EXPORT_SYMBOL(ceph_find_or_create_string);
86
87static void ceph_free_string(struct rcu_head *head)
88{
89 struct ceph_string *cs = container_of(head, struct ceph_string, rcu);
90 kfree(cs);
91}
92
93void ceph_release_string(struct kref *ref)
94{
95 struct ceph_string *cs = container_of(ref, struct ceph_string, kref);
96
97 spin_lock(&string_tree_lock);
98 if (!RB_EMPTY_NODE(&cs->node)) {
99 rb_erase(&cs->node, &string_tree);
100 RB_CLEAR_NODE(&cs->node);
101 }
102 spin_unlock(&string_tree_lock);
103
104 call_rcu(&cs->rcu, ceph_free_string);
105}
106EXPORT_SYMBOL(ceph_release_string);
107
108bool ceph_strings_empty(void)
109{
110 return RB_EMPTY_ROOT(&string_tree);
111}