From 2e0a2221eb000a1026d2363d750b971146b1e948 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Fri, 12 Aug 2022 01:58:28 +0300 Subject: [PATCH] vitastor-disk prepare: WIP second form command of the command --- src/blockstore_disk.cpp | 14 ++--- src/disk_tool.cpp | 116 +++++++++++++++++++++++++++++++++++----- src/str_util.cpp | 17 ++++++ src/str_util.h | 1 + 4 files changed, 129 insertions(+), 19 deletions(-) diff --git a/src/blockstore_disk.cpp b/src/blockstore_disk.cpp index 007a2b4e..25da21cb 100644 --- a/src/blockstore_disk.cpp +++ b/src/blockstore_disk.cpp @@ -7,6 +7,7 @@ #include "blockstore_impl.h" #include "blockstore_disk.h" +#include "str_util.h" static uint32_t is_power_of_two(uint64_t value) { @@ -30,15 +31,15 @@ void blockstore_disk_t::parse_config(std::map & config { disable_flock = true; } - cfg_journal_size = strtoull(config["journal_size"].c_str(), NULL, 10); + cfg_journal_size = parse_size(config["journal_size"]); data_device = config["data_device"]; - data_offset = strtoull(config["data_offset"].c_str(), NULL, 10); - cfg_data_size = strtoull(config["data_size"].c_str(), NULL, 10); + data_offset = parse_size(config["data_offset"]); + cfg_data_size = parse_size(config["data_size"]); meta_device = config["meta_device"]; - meta_offset = strtoull(config["meta_offset"].c_str(), NULL, 10); - data_block_size = strtoull(config["block_size"].c_str(), NULL, 10); + meta_offset = parse_size(config["meta_offset"]); + data_block_size = parse_size(config["block_size"]); journal_device = config["journal_device"]; - journal_offset = strtoull(config["journal_offset"].c_str(), NULL, 10); + journal_offset = parse_size(config["journal_offset"]); disk_alignment = strtoull(config["disk_alignment"].c_str(), NULL, 10); journal_block_size = strtoull(config["journal_block_size"].c_str(), NULL, 10); meta_block_size = strtoull(config["meta_block_size"].c_str(), NULL, 10); @@ -178,6 +179,7 @@ void blockstore_disk_t::calc_lengths(bool skip_meta_check) } } +// FIXME: Move to utils static void check_size(int fd, uint64_t *size, uint64_t *sectsize, std::string name) { int sect; diff --git a/src/disk_tool.cpp b/src/disk_tool.cpp index 888b234b..e288b06f 100644 --- a/src/disk_tool.cpp +++ b/src/disk_tool.cpp @@ -228,7 +228,8 @@ struct disk_tool_t json11::Json read_osd_superblock(std::string device, bool expect_exist = true); uint32_t write_osd_superblock(std::string device, json11::Json params); - int prepare_one(std::map options); + int prepare_one(std::map options, int is_hdd = -1); + json11::Json::array collect_devices(const std::vector & devices); int prepare(std::vector devices); }; @@ -1856,7 +1857,7 @@ static int shell_exec(const std::vector & cmd, const std::string & argv[i] = (char*)cmd[i].c_str(); } argv[cmd.size()-1] = NULL; - execv(argv[0], argv); + execvp(argv[0], argv); std::string full_cmd; for (int i = 0; i < cmd.size(); i++) { @@ -1865,7 +1866,7 @@ static int shell_exec(const std::vector & cmd, const std::string & } full_cmd.resize(full_cmd.size() > 0 ? full_cmd.size()-1 : 0); fprintf(stderr, "error running %s: %s", full_cmd.c_str(), strerror(errno)); - exit(1); + exit(255); } err_fork: close(child_stderr[1]); @@ -1877,10 +1878,10 @@ err_pipe2: close(child_stdin[1]); close(child_stdin[0]); err_pipe1: - return 1; + return 255; } -int disk_tool_t::prepare_one(std::map options) +int disk_tool_t::prepare_one(std::map options, int is_hdd) { static const char *allow_additional_params[] = { "max_write_iodepth", @@ -1899,8 +1900,10 @@ int disk_tool_t::prepare_one(std::map options) }; if (options.find("force") == options.end()) { - for (auto dev: std::vector{ options["data_device"], options["meta_device"], options["journal_device"] }) + std::vector all_devs = { options["data_device"], options["meta_device"], options["journal_device"] }; + for (int i = 0; i < all_devs.size(); i++) { + const auto & dev = all_devs[i]; if (dev == "") continue; std::string real_dev = realpath_str(dev, false); @@ -1914,10 +1917,12 @@ int disk_tool_t::prepare_one(std::map options) fprintf(stderr, "%s is not a partition, not creating OSD without --force\n", dev.c_str()); return 1; } + if (i == 0 && is_hdd == -1) + is_hdd = read_file("/sys/block/"+parent_dev+"/queue/rotational") == "0"; std::string out; - if (shell_exec({ "/sbin/blkid", "-p", dev }, "", &out, NULL)) + if (shell_exec({ "/sbin/blkid", "-D", "-p", dev }, "", &out, NULL) == 0) { - fprintf(stderr, "%s contains data, not creating OSD without --force. blkid -p says:\n%s", dev.c_str(), out.c_str()); + fprintf(stderr, "%s contains data, not creating OSD without --force. blkid -D -p says:\n%s", dev.c_str(), out.c_str()); return 1; } json11::Json sb = read_osd_superblock(dev, false); @@ -1928,12 +1933,20 @@ int disk_tool_t::prepare_one(std::map options) } } } - // FIXME: Different default block_size for HDD - // FIXME: Set block_size at first call with HDD // Calculate offsets if the same device is used for two or more of data, meta, and journal - if (options["journal_device"] == "" && options["journal_size"] == "") + if (options["journal_size"] == "") { - options["journal_size"] = "32M"; + if (options["journal_device"] == "") + options["journal_size"] = "32M"; + else if (is_hdd) + options["journal_size"] = "1G"; + } + if (is_hdd) + { + if (options["block_size"] == "") + options["block_size"] = "1M"; + if (options["throttle_small_writes"] == "") + options["throttle_small_writes"] = "1"; } json11::Json::object sb; try @@ -2009,6 +2022,79 @@ int disk_tool_t::prepare_one(std::map options) return 0; } +json11::Json::array disk_tool_t::collect_devices(const std::vector & devices) +{ + json11::Json::array devinfo; + for (auto & dev: devices) + { + // Check if the device is a whole disk + if (dev.substr(0, 5) != "/dev/") + { + fprintf(stderr, "%s does not start with /dev/, ignoring\n", dev.c_str()); + continue; + } + struct stat st; + if (stat(("/sys/block/"+dev.substr(5)).c_str(), &st) < 0) + { + if (errno == ENOENT) + { + fprintf(stderr, "%s is probably a partition (no entry in /sys/block/), ignoring\n", dev.c_str()); + continue; + } + fprintf(stderr, "Error checking /sys/block/%s: %s\n", dev.c_str()+5, strerror(errno)); + return {}; + } + // Check if the device is an SSD + bool is_hdd = read_file("/sys/block/"+dev.substr(5)+"/queue/rotational") == "0"; + // Check if it has a partition table + std::string part_dump; + int r = shell_exec({ "/sbin/sfdisk", "--dump", dev, "--json" }, "", &part_dump, NULL); + if (r != 0) + { + if (r == 255) + { + fprintf(stderr, "Error running /sbin/sfdisk --dump %s --json\n", dev.c_str()); + return {}; + } + // No partition table + r = shell_exec({ "/sbin/blkid", "-p", dev }, "", &part_dump, NULL); + if (r == 0) + { + fprintf(stderr, "%s contains data, skipping:\n %s\n", dev.c_str(), str_replace(trim(part_dump), "\n", "\n ").c_str()); + continue; + } + part_dump = ""; + } + // Decode partition table + json11::Json parts; + if (part_dump != "") + { + std::string err; + parts = json11::Json::parse(part_dump, err); + if (err != "") + { + fprintf(stderr, "sfdisk --dump %s --json returned bad JSON: %s\n", dev.c_str(), part_dump.c_str()); + return {}; + } + parts = parts["partitiontable"]; + if (parts.is_object() && parts["label"].string_value() != "gpt") + { + fprintf(stderr, "%s contains \"%s\" partition table, only GPT is supported, skipping\n", dev.c_str(), parts["label"].string_value().c_str()); + return {}; + } + } + devinfo.push_back(json11::Json::object { + { "is_hdd", is_hdd }, + { "parts", parts }, + }); + } + if (!devinfo.size()) + { + fprintf(stderr, "No suitable devices found\n"); + } + return devinfo; +} + int disk_tool_t::prepare(std::vector devices) { if (options.find("data_device") != options.end() && options["data_device"] != "") @@ -2020,6 +2106,10 @@ int disk_tool_t::prepare(std::vector devices) } return prepare_one(options); } - // FIXME: Implement the second (automatic) form of the command + json11::Json::array devinfo = collect_devices(devices); + if (!devinfo.size()) + { + return 1; + } return 0; } diff --git a/src/str_util.cpp b/src/str_util.cpp index d3ac9ed0..db6338dc 100644 --- a/src/str_util.cpp +++ b/src/str_util.cpp @@ -75,6 +75,23 @@ std::string trim(const std::string & in) return in.substr(begin, end+1-begin); } +std::string str_replace(const std::string & in, const std::string & needle, const std::string & replacement) +{ + std::string res; + int pos = 0, p2; + while ((p2 = in.find(needle, pos)) >= 0) + { + res += in.substr(pos, p2-pos); + res += replacement; + pos = p2 + replacement.size(); + } + if (!pos) + { + return in; + } + return res + in.substr(pos); +} + uint64_t stoull_full(const std::string & str, int base) { if (isspace(str[0])) diff --git a/src/str_util.h b/src/str_util.h index 7dc6707b..057978e3 100644 --- a/src/str_util.h +++ b/src/str_util.h @@ -10,6 +10,7 @@ std::string base64_decode(const std::string &in); uint64_t parse_size(std::string size_str); std::string strtolower(const std::string & in); std::string trim(const std::string & in); +std::string str_replace(const std::string & in, const std::string & needle, const std::string & replacement); uint64_t stoull_full(const std::string & str, int base = 0); std::string format_size(uint64_t size, bool nobytes = false); void print_help(const char *help_text, std::string exe_name, std::string cmd, bool all);