Skip to content

Commit 8cf896e

Browse files
committed
osd: Access/Modify epoch maps under mutex in OSDSuperblock class
The OSDSuperblock object access/modify epoch maps in multiple threads simultaneously due to that OSD is getting crashed. To avoid the crash access the maps under mutex. Fixes: https://tracker.ceph.com/issues/66819 Signed-off-by: Mohit Agrawal <[email protected]>
1 parent ded62df commit 8cf896e

File tree

5 files changed

+148
-27
lines changed

5 files changed

+148
-27
lines changed

src/crimson/osd/osd.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ void OSD::dump_status(Formatter* f) const
870870
f->dump_stream("osd_fsid") << superblock.osd_fsid;
871871
f->dump_unsigned("whoami", superblock.whoami);
872872
f->dump_string("state", pg_shard_manager.get_osd_state_string());
873-
f->dump_stream("maps") << superblock.maps;
873+
f->dump_stream("maps") << superblock.get_maps();
874874
f->dump_stream("oldest_map") << superblock.get_oldest_map();
875875
f->dump_stream("newest_map") << superblock.get_newest_map();
876876
f->dump_unsigned("cluster_osdmap_trim_lower_bound",
@@ -881,7 +881,7 @@ void OSD::dump_status(Formatter* f) const
881881
void OSD::print(std::ostream& out) const
882882
{
883883
out << "{osd." << superblock.whoami << " "
884-
<< superblock.osd_fsid << " maps " << superblock.maps
884+
<< superblock.osd_fsid << " maps " << superblock.get_maps()
885885
<< " tlb:" << superblock.cluster_osdmap_trim_lower_bound
886886
<< " pgs:" << pg_shard_manager.get_num_pgs()
887887
<< "}";
@@ -1194,7 +1194,7 @@ seastar::future<> OSD::_handle_osd_map(Ref<MOSDMap> m)
11941194
// even if this map isn't from a mon, we may have satisfied our subscription
11951195
monc->sub_got("osdmap", last);
11961196

1197-
if (!superblock.maps.empty()) {
1197+
if (!superblock.is_maps_empty()) {
11981198
pg_shard_manager.trim_maps(t, superblock);
11991199
// TODO: once we support pg splitting, update pg_num_history here
12001200
//pg_num_history.prune(superblock.get_oldest_map());

src/crimson/osd/shard_services.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ void OSDSingletonState::trim_maps(ceph::os::Transaction& t,
547547
DEBUG("removing old osdmap epoch {}", superblock.get_oldest_map());
548548
meta_coll->remove_map(t, superblock.get_oldest_map());
549549
meta_coll->remove_inc_map(t, superblock.get_oldest_map());
550-
superblock.maps.erase(superblock.get_oldest_map());
550+
superblock.erase_oldest_maps();
551551
}
552552

553553
// we should not trim past osdmaps.cached_key_lower_bound()

src/osd/OSD.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,7 +2793,7 @@ void OSD::asok_command(
27932793
f->dump_stream("osd_fsid") << superblock.osd_fsid;
27942794
f->dump_unsigned("whoami", superblock.whoami);
27952795
f->dump_string("state", get_state_name(get_state()));
2796-
f->dump_stream("maps") << superblock.maps;
2796+
f->dump_stream("maps") << superblock.get_maps();
27972797
f->dump_stream("oldest_map") << superblock.get_oldest_map();
27982798
f->dump_stream("newest_map") << superblock.get_newest_map();
27992799
f->dump_unsigned("cluster_osdmap_trim_lower_bound",
@@ -6908,7 +6908,7 @@ void OSD::start_boot()
69086908
}
69096909
dout(1) << __func__ << dendl;
69106910
set_state(STATE_PREBOOT);
6911-
dout(10) << "start_boot - have maps " << superblock.maps << dendl;
6911+
dout(10) << "start_boot - have maps " << superblock.get_maps() << dendl;
69126912
monc->get_version("osdmap", CB_OSD_GetVersion(this));
69136913
}
69146914

@@ -8106,7 +8106,7 @@ void OSD::trim_maps(epoch_t oldest)
81068106
dout(20) << " removing old osdmap epoch " << superblock.get_oldest_map() << dendl;
81078107
t.remove(coll_t::meta(), get_osdmap_pobject_name(superblock.get_oldest_map()));
81088108
t.remove(coll_t::meta(), get_inc_osdmap_pobject_name(superblock.get_oldest_map()));
8109-
superblock.maps.erase(superblock.get_oldest_map());
8109+
superblock.erase_oldest_maps();
81108110
}
81118111

81128112
service.publish_superblock(superblock);
@@ -8407,16 +8407,16 @@ void OSD::handle_osd_map(MOSDMap *m)
84078407

84088408
track_pools_and_pg_num_changes(added_maps, t);
84098409

8410-
if (!superblock.maps.empty()) {
8410+
if (!superblock.is_maps_empty()) {
84118411
trim_maps(m->cluster_osdmap_trim_lower_bound);
84128412
pg_num_history.prune(superblock.get_oldest_map());
84138413
}
84148414
superblock.insert_osdmap_epochs(first, last);
8415-
if (superblock.maps.num_intervals() > 1) {
8415+
if (superblock.get_maps_num_intervals() > 1) {
84168416
// we had a map gap and not yet trimmed all the way up to
84178417
// cluster_osdmap_trim_lower_bound
84188418
dout(10) << __func__ << " osd maps are not contiguous"
8419-
<< superblock.maps << dendl;
8419+
<< superblock.get_maps() << dendl;
84208420
}
84218421
superblock.current_epoch = last;
84228422

@@ -8486,7 +8486,7 @@ void OSD::track_pools_and_pg_num_changes(
84868486
// lastmap should be the newest_map we have.
84878487
OSDMapRef lastmap;
84888488

8489-
if (superblock.maps.empty()) {
8489+
if (superblock.is_maps_empty()) {
84908490
dout(10) << __func__ << " no maps stored, this is probably "
84918491
<< "the first start of this osd" << dendl;
84928492
lastmap = added_maps.at(first);

src/osd/osd_types.cc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5822,6 +5822,19 @@ void pg_hit_set_history_t::generate_test_instances(list<pg_hit_set_history_t*>&
58225822
ls.back()->history.push_back(pg_hit_set_info_t());
58235823
}
58245824

5825+
// -- GuardedMap --
5826+
void OSDSuperblock::GuardedMap::encode(ceph::buffer::list &bl) const
5827+
{
5828+
std::lock_guard lock(map_lock);
5829+
::encode(maps, bl);
5830+
}
5831+
5832+
void OSDSuperblock::GuardedMap::decode(ceph::buffer::list::const_iterator &bl)
5833+
{
5834+
std::lock_guard lock(map_lock);
5835+
::decode(maps, bl);
5836+
}
5837+
58255838
// -- OSDSuperblock --
58265839

58275840
void OSDSuperblock::encode(ceph::buffer::list &bl) const
@@ -5842,7 +5855,7 @@ void OSDSuperblock::encode(ceph::buffer::list &bl) const
58425855
encode(purged_snaps_last, bl);
58435856
encode(last_purged_snaps_scrub, bl);
58445857
encode(cluster_osdmap_trim_lower_bound, bl);
5845-
encode(maps, bl);
5858+
mapc.encode(bl);
58465859
ENCODE_FINISH(bl);
58475860
}
58485861

@@ -5889,7 +5902,7 @@ void OSDSuperblock::decode(ceph::buffer::list::const_iterator &bl)
58895902
cluster_osdmap_trim_lower_bound = 0;
58905903
}
58915904
if (struct_v >= 11) {
5892-
decode(maps, bl);
5905+
mapc.decode(bl);
58935906
} else {
58945907
insert_osdmap_epochs(oldest_map, newest_map);
58955908
}
@@ -5912,7 +5925,7 @@ void OSDSuperblock::dump(Formatter *f) const
59125925
f->dump_stream("last_purged_snaps_scrub") << last_purged_snaps_scrub;
59135926
f->dump_int("cluster_osdmap_trim_lower_bound",
59145927
cluster_osdmap_trim_lower_bound);
5915-
f->dump_stream("maps") << maps;
5928+
f->dump_stream("maps") << get_maps();
59165929
}
59175930

59185931
void OSDSuperblock::generate_test_instances(list<OSDSuperblock*>& o)

src/osd/osd_types.h

Lines changed: 121 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "common/Formatter.h"
5050
#include "common/hobject.h"
5151
#include "common/snap_types.h"
52+
#include "common/ceph_mutex.h"
5253
#include "common/strtol.h" // for ritoa()
5354
#include "HitSet.h"
5455
#include "librados/ListObjectImpl.h"
@@ -5662,33 +5663,133 @@ inline std::ostream& operator<<(std::ostream& out, const ObjectExtent &ex)
56625663
// ---------------------------------------
56635664

56645665
class OSDSuperblock {
5665-
public:
5666-
uuid_d cluster_fsid, osd_fsid;
5667-
int32_t whoami = -1; // my role in this fs.
5668-
epoch_t current_epoch = 0; // most recent epoch
5669-
interval_set<epoch_t> maps; // oldest/newest maps we have.
5666+
private:
5667+
class GuardedMap {
5668+
private:
5669+
mutable ceph::mutex map_lock = ceph::make_mutex("map_lock");
5670+
interval_set<epoch_t> maps;
56705671

5671-
epoch_t get_oldest_map() const {
5672+
epoch_t calc_newest_map() const {
56725673
if (!maps.empty()) {
5673-
return maps.range_start();
5674+
// maps stores [oldest_map, newest_map) (exclusive)
5675+
return maps.range_end() - 1;
56745676
}
56755677
return 0;
56765678
}
5677-
5678-
epoch_t get_newest_map() const {
5679+
epoch_t calc_oldest_map() const {
56795680
if (!maps.empty()) {
5680-
// maps stores [oldest_map, newest_map) (exclusive)
5681-
return maps.range_end() - 1;
5681+
return maps.range_start();
56825682
}
56835683
return 0;
56845684
}
5685+
public:
5686+
GuardedMap() = default;
5687+
GuardedMap(const GuardedMap& other)
5688+
: map_lock(ceph::make_mutex("map_lock"))
5689+
{
5690+
std::lock_guard l(other.map_lock); // Lock before copying shared state
5691+
maps = other.maps;
5692+
}
5693+
5694+
GuardedMap& operator=(const GuardedMap& other) {
5695+
if (this != &other) {
5696+
std::scoped_lock l(map_lock, other.map_lock);
5697+
maps = other.maps;
5698+
}
5699+
return *this;
5700+
}
5701+
5702+
GuardedMap(GuardedMap&& other)
5703+
:map_lock(ceph::make_mutex("map_lock"))
5704+
{
5705+
std::lock_guard l(other.map_lock);
5706+
maps = std::move(other.maps);
5707+
}
5708+
5709+
GuardedMap& operator=(GuardedMap&& other) noexcept {
5710+
if (this != &other) {
5711+
std::scoped_lock l(map_lock, other.map_lock);
5712+
maps = std::move(other.maps);
5713+
}
5714+
return *this;
5715+
}
5716+
5717+
bool is_maps_empty() const {
5718+
std::lock_guard lock(map_lock);
5719+
return maps.empty();
5720+
}
5721+
5722+
void erase_oldest_maps() {
5723+
std::lock_guard lock(map_lock);
5724+
maps.erase(calc_oldest_map());
5725+
}
5726+
5727+
interval_set<epoch_t>::size_type get_maps_num_intervals() const {
5728+
std::lock_guard lock(map_lock);
5729+
return maps.num_intervals();
5730+
}
5731+
5732+
interval_set<epoch_t> get_maps() const {
5733+
std::lock_guard lock(map_lock);
5734+
return maps;
5735+
}
5736+
5737+
epoch_t get_oldest_map() const {
5738+
std::lock_guard lock(map_lock);
5739+
return calc_oldest_map();
5740+
}
5741+
5742+
epoch_t get_newest_map() const {
5743+
std::lock_guard lock(map_lock);
5744+
return calc_newest_map();
5745+
}
56855746

56865747
void insert_osdmap_epochs(epoch_t first, epoch_t last) {
56875748
ceph_assert(std::cmp_less_equal(first, last));
56885749
interval_set<epoch_t> message_epochs;
56895750
message_epochs.insert(first, last - first + 1);
5751+
std::lock_guard lock(map_lock);
56905752
maps.union_of(message_epochs);
5691-
ceph_assert(last == get_newest_map());
5753+
ceph_assert(last == calc_newest_map());
5754+
}
5755+
5756+
void encode(ceph::buffer::list &bl) const;
5757+
void decode(ceph::buffer::list::const_iterator &bl);
5758+
5759+
};
5760+
WRITE_CLASS_ENCODER(GuardedMap);
5761+
GuardedMap mapc;
5762+
public:
5763+
uuid_d cluster_fsid, osd_fsid;
5764+
int32_t whoami = -1; // my role in this fs.
5765+
epoch_t current_epoch = 0; // most recent epoch
5766+
5767+
bool is_maps_empty() const {
5768+
return mapc.is_maps_empty();
5769+
}
5770+
5771+
void erase_oldest_maps() {
5772+
mapc.erase_oldest_maps();
5773+
}
5774+
5775+
interval_set<epoch_t>::size_type get_maps_num_intervals() const {
5776+
return mapc.get_maps_num_intervals();
5777+
}
5778+
5779+
interval_set<epoch_t> get_maps() const {
5780+
return mapc.get_maps();
5781+
}
5782+
5783+
epoch_t get_oldest_map() const {
5784+
return mapc.get_oldest_map();
5785+
}
5786+
5787+
epoch_t get_newest_map() const {
5788+
return mapc.get_newest_map();
5789+
}
5790+
5791+
void insert_osdmap_epochs(epoch_t first, epoch_t last) {
5792+
mapc.insert_osdmap_epochs(first, last);
56925793
}
56935794

56945795
double weight = 0.0;
@@ -5708,6 +5809,13 @@ class OSDSuperblock {
57085809
void decode(ceph::buffer::list::const_iterator &bl);
57095810
void dump(ceph::Formatter *f) const;
57105811
static void generate_test_instances(std::list<OSDSuperblock*>& o);
5812+
5813+
// Allow default operators to avoid crimson related errors
5814+
OSDSuperblock(OSDSuperblock&&) noexcept = default;
5815+
OSDSuperblock& operator=(OSDSuperblock&&) noexcept = default;
5816+
OSDSuperblock(const OSDSuperblock&) = default;
5817+
OSDSuperblock& operator=(const OSDSuperblock&) = default;
5818+
OSDSuperblock() = default;
57115819
};
57125820
WRITE_CLASS_ENCODER(OSDSuperblock)
57135821

@@ -5717,7 +5825,7 @@ inline std::ostream& operator<<(std::ostream& out, const OSDSuperblock& sb)
57175825
<< " osd." << sb.whoami
57185826
<< " " << sb.osd_fsid
57195827
<< " e" << sb.current_epoch
5720-
<< " maps " << sb.maps
5828+
<< " maps " << sb.get_maps()
57215829
<< " lci=[" << sb.mounted << "," << sb.clean_thru << "]"
57225830
<< " tlb=" << sb.cluster_osdmap_trim_lower_bound
57235831
<< ")";

0 commit comments

Comments
 (0)