From f2faf3edb37312feb14f3255b6624ac31f73c60d Mon Sep 17 00:00:00 2001 From: Jaya Prakash Date: Wed, 5 Mar 2025 21:56:37 +0000 Subject: [PATCH] os/bluestore: Implemented create-bdev-label MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Introduces a helper function create_bdev_label() and a new command create-bdev-label to write essential OSD metadata (e.g., fsid, whoami) directly into the device label at offset 0, for use on devices where support_bdev_label == false. Usage: ./bin/ceph-bluestore-tool --path dev/osd0 --dev dev/osd0/block create-bdev-label If a label already exists, the function throws an error to avoid overwriting. This lays the groundwork for eventually removing duplicated metadata from the OSD directory for devices that don’t support native bdev labels Signed-off-by: Jaya Prakash --- doc/man/8/ceph-bluestore-tool.rst | 10 +++ src/os/CMakeLists.txt | 1 + src/os/bluestore/BlueEnv.cc | 113 +++++++++++++++++++++++++++++ src/os/bluestore/BlueStore.h | 7 ++ src/os/bluestore/bluestore_tool.cc | 37 ++++++++++ 5 files changed, 168 insertions(+) create mode 100644 src/os/bluestore/BlueEnv.cc diff --git a/doc/man/8/ceph-bluestore-tool.rst b/doc/man/8/ceph-bluestore-tool.rst index e720f3a4989f0..9e1dd31ac2eca 100644 --- a/doc/man/8/ceph-bluestore-tool.rst +++ b/doc/man/8/ceph-bluestore-tool.rst @@ -35,6 +35,8 @@ Synopsis | **ceph-bluestore-tool** trim --path *osd path* | **ceph-bluestore-tool** zap-device --dev *dev path* | **ceph-bluestore-tool** revert-wal-to-plain --path *osd path* +| **ceph-bluestore-tool** create-bdev-labels --path *osd path* --dev *device* + Description @@ -171,6 +173,14 @@ Commands Changes WAL files from envelope mode to the legacy plain mode. Useful for downgrades, or if you might want to disable this new feature (bluefs_wal_envelope_mode). +:command:`create-bdev-labels` --path *osd path* --dev *device* + + Writes a bdev label to BlueStore devices that originally did not support labeling. + Reads metadata (e.g., fsid, ceph version) from --path and writes it to the device at --dev. + Only the main device (block) gets full metadata; block.db or block.wal do not. + The --dev path must be inside the --path directory, as its name determines the device role. + Use --yes-i-really-really-mean-it to recreate corrupted labels. + Options ======= diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt index 4a96f4290d61c..af65d6a7f711e 100644 --- a/src/os/CMakeLists.txt +++ b/src/os/CMakeLists.txt @@ -29,6 +29,7 @@ if(WITH_BLUESTORE) bluestore/Writer.cc bluestore/Compression.cc bluestore/BlueAdmin.cc + bluestore/BlueEnv.cc ) endif(WITH_BLUESTORE) diff --git a/src/os/bluestore/BlueEnv.cc b/src/os/bluestore/BlueEnv.cc new file mode 100644 index 0000000000000..01062a16c9d74 --- /dev/null +++ b/src/os/bluestore/BlueEnv.cc @@ -0,0 +1,113 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include +#include +#include +#include +#include +#include +#include +#include "global/global_init.h" +#include "common/ceph_argparse.h" +#include "include/stringify.h" +#include "common/errno.h" +#include "common/safe_io.h" + +#include "os/bluestore/BlueStore.h" + +using namespace std; + + +int BlueStore::create_bdev_labels(CephContext *cct, + const std::string& path, + const std::vector& devs, + std::vector* valid_positions, + bool force) +{ + std::vector metadata_files = { + "bfm_blocks", + "bfm_blocks_per_key", + "bfm_bytes_per_block", + "bfm_size", + "bluefs", + "ceph_fsid", + "ceph_version_when_created", + "created_at", + "elastic_shared_blobs", + "fsid", + "kv_backend", + "magic", + "osd_key", + "ready", + "require_osd_release", + "type", + "whoami" + }; + + unique_ptr bdev(BlockDevice::create(cct, devs.front(), nullptr, nullptr, nullptr, nullptr)); + int r = bdev->open(devs.front()); + if (r < 0) { + return r; + } + uint64_t size = bdev->get_size(); + + if (bdev->supported_bdev_label() && !force) { + bdev->close(); + return -EPERM; + } + + bdev->close(); + + bluestore_bdev_label_t label; + std::vector out_positions; + bool is_multi = false; + int64_t epoch = -1; + + r = BlueStore::read_bdev_label(cct, devs.front(), &label, + &out_positions, &is_multi, &epoch); + + if (r == 0 && !force) + return -EEXIST; + + label = bluestore_bdev_label_t(); + label.btime = ceph_clock_now(); + + if (devs.front().ends_with("block")) { + label.description = "main"; + } else if (devs.front().ends_with("block.db")) { + label.description = "bluefs db"; + } else if (devs.front().ends_with("block.wal")) { + label.description = "bluefs wal"; + } + + label.size = size; + + for (const auto& file : metadata_files) { + std::ifstream infile(path + "/" + file); + if (infile) { + std::string value((std::istreambuf_iterator(infile)), std::istreambuf_iterator()); + value.erase(std::remove(value.begin(), value.end(), '\n'), value.end()); + if (file == "fsid") { + label.osd_uuid.parse(value.c_str()); + } else if (label.description == "main") { + label.meta[file] = value; + } + } else { + cerr << "Warning: unable to read metadata file: " << file << std::endl; + } + } + + bool wrote_at_least_one = false; + for (uint64_t position : *valid_positions) { + r = BlueStore::write_bdev_label(cct, devs.front(), label, position); + if (r < 0) { + cerr << "unable to write label at 0x" << std::hex << position << std::dec + << ": " << cpp_strerror(r) << std::endl; + } else { + wrote_at_least_one = true; + } + } + return wrote_at_least_one ? 0 : -EIO; +} diff --git a/src/os/bluestore/BlueStore.h b/src/os/bluestore/BlueStore.h index 909efa568b963..bfa900d4c699b 100644 --- a/src/os/bluestore/BlueStore.h +++ b/src/os/bluestore/BlueStore.h @@ -4175,6 +4175,13 @@ private: void _fsck_check_objects(FSCKDepth depth, FSCK_ObjectCtx& ctx); + +public: + static int create_bdev_labels(CephContext *cct, + const std::string& path, + const std::vector& devs, + std::vector* valid_positions, + bool force); }; inline std::ostream& operator<<(std::ostream& out, const BlueStore::volatile_statfs& s) { diff --git a/src/os/bluestore/bluestore_tool.cc b/src/os/bluestore/bluestore_tool.cc index 9fff0a08278da..ad1f8d30841df 100644 --- a/src/os/bluestore/bluestore_tool.cc +++ b/src/os/bluestore/bluestore_tool.cc @@ -357,6 +357,7 @@ int main(int argc, char **argv) "show-label, " "show-label-at, " "set-label-key, " + "create-bdev-labels, " "rm-label-key, " "prime-osd-dir, " "bluefs-super-dump, " @@ -520,6 +521,16 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } } + if (action == "create-bdev-labels") { + if (path.empty()) { + cerr << "must specify bluestore path" << std::endl; + exit(EXIT_FAILURE); + } + if (devs.size() != 1) { + cerr << "must specify the main bluestore device" << std::endl; + exit(EXIT_FAILURE); + } + } if (action == "show-label") { if (devs.empty() && path.empty()) { cerr << "must specify bluestore path *or* raw device(s)" << std::endl; @@ -837,6 +848,32 @@ int main(int argc, char **argv) jf.close_section(); jf.flush(cout); } + else if (action == "create-bdev-labels") { + + std::vector valid_positions = {0}; + + bool force = vm.count("yes-i-really-really-mean-it"); + int r = BlueStore::create_bdev_labels(cct.get(), path, devs, &valid_positions, force); + if (r == -EPERM && !force) { + cerr << "device " << devs.front() + << " already supports bdev label refusing to create a new label without --yes-i-really-really-mean-it" + << std::endl; + exit(EXIT_FAILURE); + } + + if (r == -EEXIST && !force) { + cerr << "device " << devs.front() << " already has a label" << std::endl; + cerr << "Creating a new label on top of an existing one is a dangerous operation " + << "which could cause data loss.\n" + << "Please confirm with --yes-i-really-really-mean-it option" << std::endl; + exit(EXIT_FAILURE); + } + + if (r < 0) { + cerr << "Failed to create bdev label: " << cpp_strerror(r) << std::endl; + exit(EXIT_FAILURE); + } + } else if (action == "set-label-key") { bluestore_bdev_label_t label; std::vector valid_positions; -- 2.39.5