aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-08-02 19:39:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-02 19:39:09 -0400
commit72b5ac54d620b29cae23d25f0405f2765b466f72 (patch)
tree276e6313a16f0821cb3da7061372f37b0feb8ace /net
parentc7fac299672ee98a1da90ea2e473180fc75d2c53 (diff)
parenta0f2b65275413b3438e9f55b1427273cd893c3b2 (diff)
Merge tag 'ceph-for-4.8-rc1' of git://github.com/ceph/ceph-client
Pull Ceph updates from Ilya Dryomov: "The highlights are: - RADOS namespace support in libceph and CephFS (Zheng Yan and myself). The stopgaps added in 4.5 to deny access to inodes in namespaces are removed and CEPH_FEATURE_FS_FILE_LAYOUT_V2 feature bit is now fully supported - A large rework of the MDS cap flushing code (Zheng Yan) - Handle some of ->d_revalidate() in RCU mode (Jeff Layton). We were overly pessimistic before, bailing at the first sight of LOOKUP_RCU On top of that we've got a few CephFS bug fixes, a couple of cleanups and Arnd's workaround for a weird genksyms issue" * tag 'ceph-for-4.8-rc1' of git://github.com/ceph/ceph-client: (34 commits) ceph: fix symbol versioning for ceph_monc_do_statfs ceph: Correctly return NXIO errors from ceph_llseek ceph: Mark the file cache as unreclaimable ceph: optimize cap flush waiting ceph: cleanup ceph_flush_snaps() ceph: kick cap flushes before sending other cap message ceph: introduce an inode flag to indicates if snapflush is needed ceph: avoid sending duplicated cap flush message ceph: unify cap flush and snapcap flush ceph: use list instead of rbtree to track cap flushes ceph: update types of some local varibles ceph: include 'follows' of pending snapflush in cap reconnect message ceph: update cap reconnect message to version 3 ceph: mount non-default filesystem by name libceph: fsmap.user subscription support ceph: handle LOOKUP_RCU in ceph_d_revalidate ceph: allow dentry_lease_is_valid to work under RCU walk ceph: clear d_fsinfo pointer under d_lock ceph: remove ceph_mdsc_lease_release ceph: don't use ->d_time ...
Diffstat (limited to 'net')
-rw-r--r--net/ceph/Makefile2
-rw-r--r--net/ceph/ceph_common.c2
-rw-r--r--net/ceph/ceph_fs.c30
-rw-r--r--net/ceph/debugfs.c12
-rw-r--r--net/ceph/mon_client.c4
-rw-r--r--net/ceph/msgpool.c1
-rw-r--r--net/ceph/osd_client.c49
-rw-r--r--net/ceph/osdmap.c58
-rw-r--r--net/ceph/string_table.c111
9 files changed, 245 insertions, 24 deletions
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/ceph_fs.c b/net/ceph/ceph_fs.c
index 41466ccb972a..7d54e944de5e 100644
--- a/net/ceph/ceph_fs.c
+++ b/net/ceph/ceph_fs.c
@@ -9,9 +9,9 @@
9 */ 9 */
10int ceph_file_layout_is_valid(const struct ceph_file_layout *layout) 10int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
11{ 11{
12 __u32 su = le32_to_cpu(layout->fl_stripe_unit); 12 __u32 su = layout->stripe_unit;
13 __u32 sc = le32_to_cpu(layout->fl_stripe_count); 13 __u32 sc = layout->stripe_count;
14 __u32 os = le32_to_cpu(layout->fl_object_size); 14 __u32 os = layout->object_size;
15 15
16 /* stripe unit, object size must be non-zero, 64k increment */ 16 /* stripe unit, object size must be non-zero, 64k increment */
17 if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1))) 17 if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1)))
@@ -27,6 +27,30 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
27 return 1; 27 return 1;
28} 28}
29 29
30void ceph_file_layout_from_legacy(struct ceph_file_layout *fl,
31 struct ceph_file_layout_legacy *legacy)
32{
33 fl->stripe_unit = le32_to_cpu(legacy->fl_stripe_unit);
34 fl->stripe_count = le32_to_cpu(legacy->fl_stripe_count);
35 fl->object_size = le32_to_cpu(legacy->fl_object_size);
36 fl->pool_id = le32_to_cpu(legacy->fl_pg_pool);
37 if (fl->pool_id == 0)
38 fl->pool_id = -1;
39}
40EXPORT_SYMBOL(ceph_file_layout_from_legacy);
41
42void ceph_file_layout_to_legacy(struct ceph_file_layout *fl,
43 struct ceph_file_layout_legacy *legacy)
44{
45 legacy->fl_stripe_unit = cpu_to_le32(fl->stripe_unit);
46 legacy->fl_stripe_count = cpu_to_le32(fl->stripe_count);
47 legacy->fl_object_size = cpu_to_le32(fl->object_size);
48 if (fl->pool_id >= 0)
49 legacy->fl_pg_pool = cpu_to_le32(fl->pool_id);
50 else
51 legacy->fl_pg_pool = 0;
52}
53EXPORT_SYMBOL(ceph_file_layout_to_legacy);
30 54
31int ceph_flags_to_mode(int flags) 55int ceph_flags_to_mode(int flags)
32{ 56{
diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c
index e77b04ca7802..c62b2b029a6e 100644
--- a/net/ceph/debugfs.c
+++ b/net/ceph/debugfs.c
@@ -156,8 +156,16 @@ static void dump_target(struct seq_file *s, struct ceph_osd_request_target *t)
156 seq_printf(s, "]/%d\t[", t->up.primary); 156 seq_printf(s, "]/%d\t[", t->up.primary);
157 for (i = 0; i < t->acting.size; i++) 157 for (i = 0; i < t->acting.size; i++)
158 seq_printf(s, "%s%d", (!i ? "" : ","), t->acting.osds[i]); 158 seq_printf(s, "%s%d", (!i ? "" : ","), t->acting.osds[i]);
159 seq_printf(s, "]/%d\t%*pE\t0x%x", t->acting.primary, 159 seq_printf(s, "]/%d\t", t->acting.primary);
160 t->target_oid.name_len, t->target_oid.name, t->flags); 160 if (t->target_oloc.pool_ns) {
161 seq_printf(s, "%*pE/%*pE\t0x%x",
162 (int)t->target_oloc.pool_ns->len,
163 t->target_oloc.pool_ns->str,
164 t->target_oid.name_len, t->target_oid.name, t->flags);
165 } else {
166 seq_printf(s, "%*pE\t0x%x", t->target_oid.name_len,
167 t->target_oid.name, t->flags);
168 }
161 if (t->paused) 169 if (t->paused)
162 seq_puts(s, "\tP"); 170 seq_puts(s, "\tP");
163} 171}
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index 37c38a7fb5c5..c83326c5ba58 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -227,9 +227,10 @@ static void __schedule_delayed(struct ceph_mon_client *monc)
227} 227}
228 228
229const char *ceph_sub_str[] = { 229const char *ceph_sub_str[] = {
230 [CEPH_SUB_MDSMAP] = "mdsmap",
231 [CEPH_SUB_MONMAP] = "monmap", 230 [CEPH_SUB_MONMAP] = "monmap",
232 [CEPH_SUB_OSDMAP] = "osdmap", 231 [CEPH_SUB_OSDMAP] = "osdmap",
232 [CEPH_SUB_FSMAP] = "fsmap.user",
233 [CEPH_SUB_MDSMAP] = "mdsmap",
233}; 234};
234 235
235/* 236/*
@@ -1193,6 +1194,7 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
1193 case CEPH_MSG_MON_MAP: 1194 case CEPH_MSG_MON_MAP:
1194 case CEPH_MSG_MDS_MAP: 1195 case CEPH_MSG_MDS_MAP:
1195 case CEPH_MSG_OSD_MAP: 1196 case CEPH_MSG_OSD_MAP:
1197 case CEPH_MSG_FS_MAP_USER:
1196 m = ceph_msg_new(type, front_len, GFP_NOFS, false); 1198 m = ceph_msg_new(type, front_len, GFP_NOFS, false);
1197 if (!m) 1199 if (!m)
1198 return NULL; /* ENOMEM--return skip == 0 */ 1200 return NULL; /* ENOMEM--return skip == 0 */
diff --git a/net/ceph/msgpool.c b/net/ceph/msgpool.c
index ddec1c10ac80..aaed59a47b1d 100644
--- a/net/ceph/msgpool.c
+++ b/net/ceph/msgpool.c
@@ -5,6 +5,7 @@
5#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/vmalloc.h> 6#include <linux/vmalloc.h>
7 7
8#include <linux/ceph/messenger.h>
8#include <linux/ceph/msgpool.h> 9#include <linux/ceph/msgpool.h>
9 10
10static void *msgpool_alloc(gfp_t gfp_mask, void *arg) 11static void *msgpool_alloc(gfp_t gfp_mask, void *arg)
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 89469592076c..b5ec09612ff7 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -387,7 +387,9 @@ static void target_copy(struct ceph_osd_request_target *dest,
387static void target_destroy(struct ceph_osd_request_target *t) 387static void target_destroy(struct ceph_osd_request_target *t)
388{ 388{
389 ceph_oid_destroy(&t->base_oid); 389 ceph_oid_destroy(&t->base_oid);
390 ceph_oloc_destroy(&t->base_oloc);
390 ceph_oid_destroy(&t->target_oid); 391 ceph_oid_destroy(&t->target_oid);
392 ceph_oloc_destroy(&t->target_oloc);
391} 393}
392 394
393/* 395/*
@@ -533,6 +535,11 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
533} 535}
534EXPORT_SYMBOL(ceph_osdc_alloc_request); 536EXPORT_SYMBOL(ceph_osdc_alloc_request);
535 537
538static int ceph_oloc_encoding_size(struct ceph_object_locator *oloc)
539{
540 return 8 + 4 + 4 + 4 + (oloc->pool_ns ? oloc->pool_ns->len : 0);
541}
542
536int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp) 543int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp)
537{ 544{
538 struct ceph_osd_client *osdc = req->r_osdc; 545 struct ceph_osd_client *osdc = req->r_osdc;
@@ -540,11 +547,13 @@ int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp)
540 int msg_size; 547 int msg_size;
541 548
542 WARN_ON(ceph_oid_empty(&req->r_base_oid)); 549 WARN_ON(ceph_oid_empty(&req->r_base_oid));
550 WARN_ON(ceph_oloc_empty(&req->r_base_oloc));
543 551
544 /* create request message */ 552 /* create request message */
545 msg_size = 4 + 4 + 4; /* client_inc, osdmap_epoch, flags */ 553 msg_size = 4 + 4 + 4; /* client_inc, osdmap_epoch, flags */
546 msg_size += 4 + 4 + 4 + 8; /* mtime, reassert_version */ 554 msg_size += 4 + 4 + 4 + 8; /* mtime, reassert_version */
547 msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */ 555 msg_size += CEPH_ENCODING_START_BLK_LEN +
556 ceph_oloc_encoding_size(&req->r_base_oloc); /* oloc */
548 msg_size += 1 + 8 + 4 + 4; /* pgid */ 557 msg_size += 1 + 8 + 4 + 4; /* pgid */
549 msg_size += 4 + req->r_base_oid.name_len; /* oid */ 558 msg_size += 4 + req->r_base_oid.name_len; /* oid */
550 msg_size += 2 + req->r_num_ops * sizeof(struct ceph_osd_op); 559 msg_size += 2 + req->r_num_ops * sizeof(struct ceph_osd_op);
@@ -932,7 +941,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
932 if (opcode == CEPH_OSD_OP_CREATE || opcode == CEPH_OSD_OP_DELETE) { 941 if (opcode == CEPH_OSD_OP_CREATE || opcode == CEPH_OSD_OP_DELETE) {
933 osd_req_op_init(req, which, opcode, 0); 942 osd_req_op_init(req, which, opcode, 0);
934 } else { 943 } else {
935 u32 object_size = le32_to_cpu(layout->fl_object_size); 944 u32 object_size = layout->object_size;
936 u32 object_base = off - objoff; 945 u32 object_base = off - objoff;
937 if (!(truncate_seq == 1 && truncate_size == -1ULL)) { 946 if (!(truncate_seq == 1 && truncate_size == -1ULL)) {
938 if (truncate_size <= object_base) { 947 if (truncate_size <= object_base) {
@@ -948,7 +957,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
948 } 957 }
949 958
950 req->r_flags = flags; 959 req->r_flags = flags;
951 req->r_base_oloc.pool = ceph_file_layout_pg_pool(*layout); 960 req->r_base_oloc.pool = layout->pool_id;
961 req->r_base_oloc.pool_ns = ceph_try_get_string(layout->pool_ns);
952 ceph_oid_printf(&req->r_base_oid, "%llx.%08llx", vino.ino, objnum); 962 ceph_oid_printf(&req->r_base_oid, "%llx.%08llx", vino.ino, objnum);
953 963
954 req->r_snapid = vino.snap; 964 req->r_snapid = vino.snap;
@@ -1489,12 +1499,16 @@ static void encode_request(struct ceph_osd_request *req, struct ceph_msg *msg)
1489 p += sizeof(req->r_replay_version); 1499 p += sizeof(req->r_replay_version);
1490 1500
1491 /* oloc */ 1501 /* oloc */
1492 ceph_encode_8(&p, 4); 1502 ceph_start_encoding(&p, 5, 4,
1493 ceph_encode_8(&p, 4); 1503 ceph_oloc_encoding_size(&req->r_t.target_oloc));
1494 ceph_encode_32(&p, 8 + 4 + 4);
1495 ceph_encode_64(&p, req->r_t.target_oloc.pool); 1504 ceph_encode_64(&p, req->r_t.target_oloc.pool);
1496 ceph_encode_32(&p, -1); /* preferred */ 1505 ceph_encode_32(&p, -1); /* preferred */
1497 ceph_encode_32(&p, 0); /* key len */ 1506 ceph_encode_32(&p, 0); /* key len */
1507 if (req->r_t.target_oloc.pool_ns)
1508 ceph_encode_string(&p, end, req->r_t.target_oloc.pool_ns->str,
1509 req->r_t.target_oloc.pool_ns->len);
1510 else
1511 ceph_encode_32(&p, 0);
1498 1512
1499 /* pgid */ 1513 /* pgid */
1500 ceph_encode_8(&p, 1); 1514 ceph_encode_8(&p, 1);
@@ -2594,9 +2608,22 @@ static int ceph_oloc_decode(void **p, void *end,
2594 } 2608 }
2595 2609
2596 if (struct_v >= 5) { 2610 if (struct_v >= 5) {
2611 bool changed = false;
2612
2597 len = ceph_decode_32(p); 2613 len = ceph_decode_32(p);
2598 if (len > 0) { 2614 if (len > 0) {
2599 pr_warn("ceph_object_locator::nspace is set\n"); 2615 ceph_decode_need(p, end, len, e_inval);
2616 if (!oloc->pool_ns ||
2617 ceph_compare_string(oloc->pool_ns, *p, len))
2618 changed = true;
2619 *p += len;
2620 } else {
2621 if (oloc->pool_ns)
2622 changed = true;
2623 }
2624 if (changed) {
2625 /* redirect changes namespace */
2626 pr_warn("ceph_object_locator::nspace is changed\n");
2600 goto e_inval; 2627 goto e_inval;
2601 } 2628 }
2602 } 2629 }
@@ -2806,7 +2833,9 @@ static void handle_reply(struct ceph_osd *osd, struct ceph_msg *msg)
2806 goto out_unlock_session; 2833 goto out_unlock_session;
2807 } 2834 }
2808 2835
2836 m.redirect.oloc.pool_ns = req->r_t.target_oloc.pool_ns;
2809 ret = decode_MOSDOpReply(msg, &m); 2837 ret = decode_MOSDOpReply(msg, &m);
2838 m.redirect.oloc.pool_ns = NULL;
2810 if (ret) { 2839 if (ret) {
2811 pr_err("failed to decode MOSDOpReply for tid %llu: %d\n", 2840 pr_err("failed to decode MOSDOpReply for tid %llu: %d\n",
2812 req->r_tid, ret); 2841 req->r_tid, ret);
@@ -2835,7 +2864,11 @@ static void handle_reply(struct ceph_osd *osd, struct ceph_msg *msg)
2835 unlink_request(osd, req); 2864 unlink_request(osd, req);
2836 mutex_unlock(&osd->lock); 2865 mutex_unlock(&osd->lock);
2837 2866
2838 ceph_oloc_copy(&req->r_t.target_oloc, &m.redirect.oloc); 2867 /*
2868 * Not ceph_oloc_copy() - changing pool_ns is not
2869 * supported.
2870 */
2871 req->r_t.target_oloc.pool = m.redirect.oloc.pool;
2839 req->r_flags |= CEPH_OSD_FLAG_REDIRECTED; 2872 req->r_flags |= CEPH_OSD_FLAG_REDIRECTED;
2840 req->r_tid = 0; 2873 req->r_tid = 0;
2841 __submit_request(req, false); 2874 __submit_request(req, false);
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index 7e480bf75bcf..d2436880b305 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -1510,6 +1510,24 @@ bad:
1510 return ERR_PTR(err); 1510 return ERR_PTR(err);
1511} 1511}
1512 1512
1513void ceph_oloc_copy(struct ceph_object_locator *dest,
1514 const struct ceph_object_locator *src)
1515{
1516 WARN_ON(!ceph_oloc_empty(dest));
1517 WARN_ON(dest->pool_ns); /* empty() only covers ->pool */
1518
1519 dest->pool = src->pool;
1520 if (src->pool_ns)
1521 dest->pool_ns = ceph_get_string(src->pool_ns);
1522}
1523EXPORT_SYMBOL(ceph_oloc_copy);
1524
1525void ceph_oloc_destroy(struct ceph_object_locator *oloc)
1526{
1527 ceph_put_string(oloc->pool_ns);
1528}
1529EXPORT_SYMBOL(ceph_oloc_destroy);
1530
1513void ceph_oid_copy(struct ceph_object_id *dest, 1531void ceph_oid_copy(struct ceph_object_id *dest,
1514 const struct ceph_object_id *src) 1532 const struct ceph_object_id *src)
1515{ 1533{
@@ -1770,9 +1788,9 @@ int ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
1770 u64 *ono, 1788 u64 *ono,
1771 u64 *oxoff, u64 *oxlen) 1789 u64 *oxoff, u64 *oxlen)
1772{ 1790{
1773 u32 osize = le32_to_cpu(layout->fl_object_size); 1791 u32 osize = layout->object_size;
1774 u32 su = le32_to_cpu(layout->fl_stripe_unit); 1792 u32 su = layout->stripe_unit;
1775 u32 sc = le32_to_cpu(layout->fl_stripe_count); 1793 u32 sc = layout->stripe_count;
1776 u32 bl, stripeno, stripepos, objsetno; 1794 u32 bl, stripeno, stripepos, objsetno;
1777 u32 su_per_object; 1795 u32 su_per_object;
1778 u64 t, su_offset; 1796 u64 t, su_offset;
@@ -1844,12 +1862,34 @@ int ceph_object_locator_to_pg(struct ceph_osdmap *osdmap,
1844 if (!pi) 1862 if (!pi)
1845 return -ENOENT; 1863 return -ENOENT;
1846 1864
1847 raw_pgid->pool = oloc->pool; 1865 if (!oloc->pool_ns) {
1848 raw_pgid->seed = ceph_str_hash(pi->object_hash, oid->name, 1866 raw_pgid->pool = oloc->pool;
1849 oid->name_len); 1867 raw_pgid->seed = ceph_str_hash(pi->object_hash, oid->name,
1850 1868 oid->name_len);
1851 dout("%s %s -> raw_pgid %llu.%x\n", __func__, oid->name, 1869 dout("%s %s -> raw_pgid %llu.%x\n", __func__, oid->name,
1852 raw_pgid->pool, raw_pgid->seed); 1870 raw_pgid->pool, raw_pgid->seed);
1871 } else {
1872 char stack_buf[256];
1873 char *buf = stack_buf;
1874 int nsl = oloc->pool_ns->len;
1875 size_t total = nsl + 1 + oid->name_len;
1876
1877 if (total > sizeof(stack_buf)) {
1878 buf = kmalloc(total, GFP_NOIO);
1879 if (!buf)
1880 return -ENOMEM;
1881 }
1882 memcpy(buf, oloc->pool_ns->str, nsl);
1883 buf[nsl] = '\037';
1884 memcpy(buf + nsl + 1, oid->name, oid->name_len);
1885 raw_pgid->pool = oloc->pool;
1886 raw_pgid->seed = ceph_str_hash(pi->object_hash, buf, total);
1887 if (buf != stack_buf)
1888 kfree(buf);
1889 dout("%s %s ns %.*s -> raw_pgid %llu.%x\n", __func__,
1890 oid->name, nsl, oloc->pool_ns->str,
1891 raw_pgid->pool, raw_pgid->seed);
1892 }
1853 return 0; 1893 return 0;
1854} 1894}
1855EXPORT_SYMBOL(ceph_object_locator_to_pg); 1895EXPORT_SYMBOL(ceph_object_locator_to_pg);
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}