From 8e12285629aca41da89d41fee265eb923f34dece Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Tue, 27 Dec 2022 01:42:13 +0300 Subject: [PATCH] Fix vitastor-disk purge (now it works) --- docs/usage/disk.en.md | 4 +-- docs/usage/disk.ru.md | 4 +-- src/disk_tool.cpp | 4 +-- src/disk_tool.h | 2 +- src/disk_tool_prepare.cpp | 11 ++++-- src/disk_tool_udev.cpp | 72 ++++++++++++++++++++++++++------------- src/disk_tool_upgrade.cpp | 36 -------------------- src/disk_tool_utils.cpp | 42 +++++++++++++++++++++-- 8 files changed, 104 insertions(+), 71 deletions(-) diff --git a/docs/usage/disk.en.md b/docs/usage/disk.en.md index cca7a73b..13e46b34 100644 --- a/docs/usage/disk.en.md +++ b/docs/usage/disk.en.md @@ -164,14 +164,14 @@ Purge Vitastor OSD(s) on specified device(s). Uses `vitastor-cli rm-osd` to chec if deletion is possible without data loss and to actually remove metadata from etcd. `--force` and `--allow-data-loss` options may be used to ignore safety check results. -Requires `vitastor-cli` and `wipefs` utilities. +Requires `vitastor-cli`, `sfdisk` and `partprobe` (from parted) utilities. ## read-sb `vitastor-disk read-sb [--force] ` Try to read Vitastor OSD superblock from `` and print it in JSON format. -`--force` allows to bypass "does not refer to the device itself" errors. +`--force` allows to ignore validation errors. ## write-sb diff --git a/docs/usage/disk.ru.md b/docs/usage/disk.ru.md index d41fa137..af9dc568 100644 --- a/docs/usage/disk.ru.md +++ b/docs/usage/disk.ru.md @@ -167,7 +167,7 @@ throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us. возможности удаления без потери данных и для удаления OSD из etcd. Опции `--force` и `--allow-data-loss` служат для обхода данной защиты в случае необходимости. -Команде требуются утилиты `vitastor-cli` и `wipefs`. +Команде требуются утилиты `vitastor-cli`, `sfdisk` и `partprobe` (из состава parted). ## read-sb @@ -176,7 +176,7 @@ throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us. Прочитать суперблок OSD с диска `` и вывести его в формате JSON. Опция `--force` позволяет читать суперблок, даже если он считается некорректным -из-за того, что не ссылается на устройство, с которого прочитан. +из-за ошибок валидации. ## write-sb diff --git a/src/disk_tool.cpp b/src/disk_tool.cpp index e28296fd..a0c6bc59 100644 --- a/src/disk_tool.cpp +++ b/src/disk_tool.cpp @@ -115,11 +115,11 @@ static const char *help_text = " if deletion is possible without data loss and to actually remove metadata from etcd.\n" " --force and --allow-data-loss options may be used to ignore safety check results.\n" " \n" - " Requires `vitastor-cli` and `wipefs` utilities.\n" + " Requires `vitastor-cli`, `sfdisk` and `partprobe` (from parted) utilities.\n" "\n" "vitastor-disk read-sb [--force] \n" " Try to read Vitastor OSD superblock from and print it in JSON format.\n" - " --force allows to bypass \"does not refer to the device itself\" errors.\n" + " --force allows to ignore validation errors.\n" "\n" "vitastor-disk write-sb \n" " Read JSON from STDIN and write it into Vitastor OSD superblock on .\n" diff --git a/src/disk_tool.h b/src/disk_tool.h index 8f54d6d1..153bb841 100644 --- a/src/disk_tool.h +++ b/src/disk_tool.h @@ -109,7 +109,6 @@ struct disk_tool_t int write_sb(std::string device); int exec_osd(std::string device); int systemd_start_stop_osds(const std::vector & cmd, const std::vector & devices); - int call_systemctl(const std::vector & cmd, const std::vector & osd_numbers); int pre_exec_osd(std::string device); int purge_devices(const std::vector & devices); @@ -141,3 +140,4 @@ int write_zero(int fd, uint64_t offset, uint64_t size); json11::Json read_parttable(std::string dev); uint64_t dev_size_from_parttable(json11::Json pt); uint64_t free_from_parttable(json11::Json pt); +int fix_partition_type(std::string dev_by_uuid); diff --git a/src/disk_tool_prepare.cpp b/src/disk_tool_prepare.cpp index 1e404c87..8ce4fe30 100644 --- a/src/disk_tool_prepare.cpp +++ b/src/disk_tool_prepare.cpp @@ -61,6 +61,11 @@ int disk_tool_t::prepare_one(std::map options, int is_ fprintf(stderr, "%s already contains Vitastor OSD superblock, not creating OSD without --force\n", dev.c_str()); return 1; } + if (fix_partition_type(dev) != 0) + { + fprintf(stderr, "%s has incorrect type and we failed to change it to Vitastor type\n", dev.c_str()); + return 1; + } } } for (auto dev: std::vector{"data", "meta", "journal"}) @@ -317,7 +322,8 @@ json11::Json disk_tool_t::add_partitions(vitastor_dev_info_t & devinfo, std::vec { script += "+ "+size+" "+std::string(VITASTOR_PART_TYPE)+"\n"; } - if (shell_exec({ "sfdisk", "--force", devinfo.path }, script, NULL, NULL) != 0) + std::string out; + if (shell_exec({ "sfdisk", "--no-reread", "--force", devinfo.path }, script, &out, NULL) != 0) { fprintf(stderr, "Failed to add %lu partition(s) with sfdisk\n", sizes.size()); return {}; @@ -351,7 +357,8 @@ json11::Json disk_tool_t::add_partitions(vitastor_dev_info_t & devinfo, std::vec { iter++; // Run partprobe - if (iter > 1 || (r = shell_exec({ "partprobe", devinfo.path }, "", NULL, NULL)) != 0) + std::string out; + if (iter > 1 || (r = shell_exec({ "partprobe", devinfo.path }, "", &out, NULL)) != 0) { fprintf( stderr, iter == 1 && r == 255 diff --git a/src/disk_tool_udev.cpp b/src/disk_tool_udev.cpp index 34fbf7d8..354e9344 100644 --- a/src/disk_tool_udev.cpp +++ b/src/disk_tool_udev.cpp @@ -5,6 +5,7 @@ #include "disk_tool.h" #include "rw_blocking.h" +#include "str_util.h" struct __attribute__((__packed__)) vitastor_disk_superblock_t { @@ -123,7 +124,7 @@ uint32_t disk_tool_t::write_osd_superblock(std::string device, json11::Json para return sb_size; } -json11::Json disk_tool_t::read_osd_superblock(std::string device, bool expect_exist, bool ignore_nonref) +json11::Json disk_tool_t::read_osd_superblock(std::string device, bool expect_exist, bool ignore_errors) { vitastor_disk_superblock_t *sb = NULL; uint8_t *buf = NULL; @@ -144,7 +145,7 @@ json11::Json disk_tool_t::read_osd_superblock(std::string device, bool expect_ex goto ex; } sb = (vitastor_disk_superblock_t*)buf; - if (sb->magic != VITASTOR_DISK_MAGIC) + if (sb->magic != VITASTOR_DISK_MAGIC && !ignore_errors) { if (expect_exist) fprintf(stderr, "Invalid OSD superblock on %s: magic number mismatch\n", device.c_str()); @@ -172,7 +173,7 @@ json11::Json disk_tool_t::read_osd_superblock(std::string device, bool expect_ex } sb = (vitastor_disk_superblock_t*)buf; } - if (sb->crc32c != crc32c(0, &sb->size, sb->size - ((uint8_t*)&sb->size - buf))) + if (sb->crc32c != crc32c(0, &sb->size, sb->size - ((uint8_t*)&sb->size - buf)) && !ignore_errors) { if (expect_exist) fprintf(stderr, "Invalid OSD superblock on %s: crc32 mismatch\n", device.c_str()); @@ -186,14 +187,14 @@ json11::Json disk_tool_t::read_osd_superblock(std::string device, bool expect_ex goto ex; } // Validate superblock - if (!osd_params["osd_num"].uint64_value()) + if (!osd_params["osd_num"].uint64_value() && !ignore_errors) { if (expect_exist) fprintf(stderr, "OSD superblock on %s lacks osd_num\n", device.c_str()); osd_params = json11::Json(); goto ex; } - if (osd_params["data_device"].string_value() == "") + if (osd_params["data_device"].string_value() == "" && !ignore_errors) { if (expect_exist) fprintf(stderr, "OSD superblock on %s lacks data_device\n", device.c_str()); @@ -226,7 +227,7 @@ json11::Json disk_tool_t::read_osd_superblock(std::string device, bool expect_ex { device_type = "journal"; } - else if (!ignore_nonref) + else if (!ignore_errors) { if (expect_exist) fprintf(stderr, "Invalid OSD superblock on %s: does not refer to the device itself\n", device.c_str()); @@ -253,29 +254,19 @@ int disk_tool_t::systemd_start_stop_osds(const std::vector & cmd, c fprintf(stderr, "Device path is missing\n"); return 1; } - std::vector osd_numbers; + std::vector svcs; for (auto & device: devices) { json11::Json sb = read_osd_superblock(device); if (!sb.is_null()) { - osd_numbers.push_back(sb["params"]["osd_num"].uint64_value()); + svcs.push_back("vitastor-osd@"+sb["params"]["osd_num"].as_string()); } } - return call_systemctl(cmd, osd_numbers); -} - -int disk_tool_t::call_systemctl(const std::vector & cmd, const std::vector & osd_numbers) -{ - if (!osd_numbers.size()) + if (!svcs.size()) { return 1; } - std::vector svcs; - for (auto osd_num: osd_numbers) - { - svcs.push_back("vitastor-osd@"+std::to_string(osd_num)); - } std::vector argv; argv.push_back((char*)"systemctl"); for (auto & s: cmd) @@ -316,8 +307,7 @@ int disk_tool_t::exec_osd(std::string device) argv[i] = (char*)argstr[i].c_str(); } argv[argstr.size()] = NULL; - execvpe(osd_binary.c_str(), argv, environ); - return 0; + return execvpe(osd_binary.c_str(), argv, environ); } static int check_disabled_cache(std::string dev) @@ -404,7 +394,12 @@ int disk_tool_t::purge_devices(const std::vector & devices) return 1; } // Disable & stop OSDs - if (call_systemctl({ "disable", "--now" }, osd_numbers) != 0) + std::vector systemctl_cli = { "systemctl", "disable", "--now" }; + for (auto osd_num: osd_numbers) + { + systemctl_cli.push_back("vitastor-osd@"+std::to_string(osd_num)); + } + if (shell_exec(systemctl_cli, "", NULL, NULL) != 0) { return 1; } @@ -464,7 +459,38 @@ int disk_tool_t::purge_devices(const std::vector & devices) if (sb["params"][dev_type+"_device"].string_value().substr(0, 22) == "/dev/disk/by-partuuid/") { // Delete the partition itself - shell_exec({ "wipefs", "-af", dev }, "", NULL, NULL); + auto uuid_to_del = strtolower(sb["params"][dev_type+"_device"].string_value().substr(22)); + auto parent_dev = get_parent_device(dev); + if (parent_dev == "" || parent_dev == dev) + { + fprintf(stderr, "Failed to delete partition %s: failed to find parent device\n", dev.c_str()); + continue; + } + auto pt = read_parttable("/dev/"+parent_dev); + if (!pt.is_object()) + continue; + json11::Json::array newpt = pt["partitions"].array_items(); + for (int i = 0; i < newpt.size(); i++) + { + if (strtolower(newpt[i]["uuid"].string_value()) == uuid_to_del) + { + auto old_part = newpt[i]; + newpt.erase(newpt.begin()+i, newpt.begin()+i+1); + vitastor_dev_info_t devinfo = { + .path = "/dev/"+parent_dev, + .pt = json11::Json::object{ { "partitions", newpt } }, + }; + add_partitions(devinfo, {}); + struct stat st; + if (stat(old_part["node"].string_value().c_str(), &st) == 0 || + errno != ENOENT) + { + std::string out; + shell_exec({ "partprobe", "/dev/"+parent_dev }, "", &out, NULL); + } + break; + } + } } } } diff --git a/src/disk_tool_upgrade.cpp b/src/disk_tool_upgrade.cpp index 60aec357..c18aae9f 100644 --- a/src/disk_tool_upgrade.cpp +++ b/src/disk_tool_upgrade.cpp @@ -38,42 +38,6 @@ static std::map read_vitastor_unit(std::string unit) return r; } -static int fix_partition_type(std::string dev_by_uuid) -{ - auto uuid = strtolower(dev_by_uuid.substr(dev_by_uuid.rfind('/')+1)); - std::string parent_dev = get_parent_device(realpath_str(dev_by_uuid, false)); - if (parent_dev == "") - return 1; - auto pt = read_parttable("/dev/"+parent_dev); - if (pt.is_null()) - return 1; - std::string script = "label: gpt\n\n"; - for (const auto & part: pt["partitions"].array_items()) - { - bool this_part = (strtolower(part["uuid"].string_value()) == uuid); - if (this_part && strtolower(part["type"].string_value()) == "e7009fac-a5a1-4d72-af72-53de13059903") - { - // Already correct type - return 0; - } - script += part["node"].string_value()+": "; - bool first = true; - for (const auto & kv: part.object_items()) - { - if (kv.first != "node") - { - script += (first ? "" : ", ")+kv.first+"="+ - (kv.first == "type" && this_part - ? "e7009fac-a5a1-4d72-af72-53de13059903" - : (kv.second.is_string() ? kv.second.string_value() : kv.second.dump())); - first = false; - } - } - script += "\n"; - } - return shell_exec({ "sfdisk", "--no-reread", "--force", "/dev/"+parent_dev }, script, NULL, NULL); -} - int disk_tool_t::upgrade_simple_unit(std::string unit) { if (stoull_full(unit) != 0) diff --git a/src/disk_tool_utils.cpp b/src/disk_tool_utils.cpp index d9c7bff7..1fd548c4 100644 --- a/src/disk_tool_utils.cpp +++ b/src/disk_tool_utils.cpp @@ -239,7 +239,8 @@ int shell_exec(const std::vector & cmd, const std::string & in, std { // Child dup2(child_stdin[0], 0); - dup2(child_stdout[1], 1); + if (out) + dup2(child_stdout[1], 1); if (err) dup2(child_stderr[1], 2); close(child_stdin[0]); @@ -250,9 +251,7 @@ int shell_exec(const std::vector & cmd, const std::string & in, std close(child_stderr[1]); char *argv[cmd.size()+1]; for (int i = 0; i < cmd.size(); i++) - { argv[i] = (char*)cmd[i].c_str(); - } argv[cmd.size()] = NULL; execvp(argv[0], argv); std::string full_cmd; @@ -354,3 +353,40 @@ uint64_t free_from_parttable(json11::Json pt) free *= pt["sectorsize"].uint64_value(); return free; } + +int fix_partition_type(std::string dev_by_uuid) +{ + auto uuid = strtolower(dev_by_uuid.substr(dev_by_uuid.rfind('/')+1)); + std::string parent_dev = get_parent_device(realpath_str(dev_by_uuid, false)); + if (parent_dev == "") + return 1; + auto pt = read_parttable("/dev/"+parent_dev); + if (pt.is_null() || pt.is_bool()) + return 1; + std::string script = "label: gpt\n\n"; + for (const auto & part: pt["partitions"].array_items()) + { + bool this_part = (strtolower(part["uuid"].string_value()) == uuid); + if (this_part && strtolower(part["type"].string_value()) == "e7009fac-a5a1-4d72-af72-53de13059903") + { + // Already correct type + return 0; + } + script += part["node"].string_value()+": "; + bool first = true; + for (const auto & kv: part.object_items()) + { + if (kv.first != "node") + { + script += (first ? "" : ", ")+kv.first+"="+ + (kv.first == "type" && this_part + ? "e7009fac-a5a1-4d72-af72-53de13059903" + : (kv.second.is_string() ? kv.second.string_value() : kv.second.dump())); + first = false; + } + } + script += "\n"; + } + std::string out; + return shell_exec({ "sfdisk", "--no-reread", "--force", "/dev/"+parent_dev }, script, &out, NULL); +}