forked from vitalif/vitastor
vitastor-disk prepare: WIP second form command of the command
parent
5a10d135f3
commit
2e0a2221eb
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "blockstore_impl.h"
|
#include "blockstore_impl.h"
|
||||||
#include "blockstore_disk.h"
|
#include "blockstore_disk.h"
|
||||||
|
#include "str_util.h"
|
||||||
|
|
||||||
static uint32_t is_power_of_two(uint64_t value)
|
static uint32_t is_power_of_two(uint64_t value)
|
||||||
{
|
{
|
||||||
|
@ -30,15 +31,15 @@ void blockstore_disk_t::parse_config(std::map<std::string, std::string> & config
|
||||||
{
|
{
|
||||||
disable_flock = true;
|
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_device = config["data_device"];
|
||||||
data_offset = strtoull(config["data_offset"].c_str(), NULL, 10);
|
data_offset = parse_size(config["data_offset"]);
|
||||||
cfg_data_size = strtoull(config["data_size"].c_str(), NULL, 10);
|
cfg_data_size = parse_size(config["data_size"]);
|
||||||
meta_device = config["meta_device"];
|
meta_device = config["meta_device"];
|
||||||
meta_offset = strtoull(config["meta_offset"].c_str(), NULL, 10);
|
meta_offset = parse_size(config["meta_offset"]);
|
||||||
data_block_size = strtoull(config["block_size"].c_str(), NULL, 10);
|
data_block_size = parse_size(config["block_size"]);
|
||||||
journal_device = config["journal_device"];
|
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);
|
disk_alignment = strtoull(config["disk_alignment"].c_str(), NULL, 10);
|
||||||
journal_block_size = strtoull(config["journal_block_size"].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);
|
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)
|
static void check_size(int fd, uint64_t *size, uint64_t *sectsize, std::string name)
|
||||||
{
|
{
|
||||||
int sect;
|
int sect;
|
||||||
|
|
|
@ -228,7 +228,8 @@ struct disk_tool_t
|
||||||
json11::Json read_osd_superblock(std::string device, bool expect_exist = true);
|
json11::Json read_osd_superblock(std::string device, bool expect_exist = true);
|
||||||
uint32_t write_osd_superblock(std::string device, json11::Json params);
|
uint32_t write_osd_superblock(std::string device, json11::Json params);
|
||||||
|
|
||||||
int prepare_one(std::map<std::string, std::string> options);
|
int prepare_one(std::map<std::string, std::string> options, int is_hdd = -1);
|
||||||
|
json11::Json::array collect_devices(const std::vector<std::string> & devices);
|
||||||
int prepare(std::vector<std::string> devices);
|
int prepare(std::vector<std::string> devices);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1856,7 +1857,7 @@ static int shell_exec(const std::vector<std::string> & cmd, const std::string &
|
||||||
argv[i] = (char*)cmd[i].c_str();
|
argv[i] = (char*)cmd[i].c_str();
|
||||||
}
|
}
|
||||||
argv[cmd.size()-1] = NULL;
|
argv[cmd.size()-1] = NULL;
|
||||||
execv(argv[0], argv);
|
execvp(argv[0], argv);
|
||||||
std::string full_cmd;
|
std::string full_cmd;
|
||||||
for (int i = 0; i < cmd.size(); i++)
|
for (int i = 0; i < cmd.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -1865,7 +1866,7 @@ static int shell_exec(const std::vector<std::string> & cmd, const std::string &
|
||||||
}
|
}
|
||||||
full_cmd.resize(full_cmd.size() > 0 ? full_cmd.size()-1 : 0);
|
full_cmd.resize(full_cmd.size() > 0 ? full_cmd.size()-1 : 0);
|
||||||
fprintf(stderr, "error running %s: %s", full_cmd.c_str(), strerror(errno));
|
fprintf(stderr, "error running %s: %s", full_cmd.c_str(), strerror(errno));
|
||||||
exit(1);
|
exit(255);
|
||||||
}
|
}
|
||||||
err_fork:
|
err_fork:
|
||||||
close(child_stderr[1]);
|
close(child_stderr[1]);
|
||||||
|
@ -1877,10 +1878,10 @@ err_pipe2:
|
||||||
close(child_stdin[1]);
|
close(child_stdin[1]);
|
||||||
close(child_stdin[0]);
|
close(child_stdin[0]);
|
||||||
err_pipe1:
|
err_pipe1:
|
||||||
return 1;
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
int disk_tool_t::prepare_one(std::map<std::string, std::string> options)
|
int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_hdd)
|
||||||
{
|
{
|
||||||
static const char *allow_additional_params[] = {
|
static const char *allow_additional_params[] = {
|
||||||
"max_write_iodepth",
|
"max_write_iodepth",
|
||||||
|
@ -1899,8 +1900,10 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> options)
|
||||||
};
|
};
|
||||||
if (options.find("force") == options.end())
|
if (options.find("force") == options.end())
|
||||||
{
|
{
|
||||||
for (auto dev: std::vector<std::string>{ options["data_device"], options["meta_device"], options["journal_device"] })
|
std::vector<std::string> 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 == "")
|
if (dev == "")
|
||||||
continue;
|
continue;
|
||||||
std::string real_dev = realpath_str(dev, false);
|
std::string real_dev = realpath_str(dev, false);
|
||||||
|
@ -1914,10 +1917,12 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> options)
|
||||||
fprintf(stderr, "%s is not a partition, not creating OSD without --force\n", dev.c_str());
|
fprintf(stderr, "%s is not a partition, not creating OSD without --force\n", dev.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (i == 0 && is_hdd == -1)
|
||||||
|
is_hdd = read_file("/sys/block/"+parent_dev+"/queue/rotational") == "0";
|
||||||
std::string out;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
json11::Json sb = read_osd_superblock(dev, false);
|
json11::Json sb = read_osd_superblock(dev, false);
|
||||||
|
@ -1928,12 +1933,20 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> 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
|
// 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;
|
json11::Json::object sb;
|
||||||
try
|
try
|
||||||
|
@ -2009,6 +2022,79 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> options)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json11::Json::array disk_tool_t::collect_devices(const std::vector<std::string> & 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<std::string> devices)
|
int disk_tool_t::prepare(std::vector<std::string> devices)
|
||||||
{
|
{
|
||||||
if (options.find("data_device") != options.end() && options["data_device"] != "")
|
if (options.find("data_device") != options.end() && options["data_device"] != "")
|
||||||
|
@ -2020,6 +2106,10 @@ int disk_tool_t::prepare(std::vector<std::string> devices)
|
||||||
}
|
}
|
||||||
return prepare_one(options);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,23 @@ std::string trim(const std::string & in)
|
||||||
return in.substr(begin, end+1-begin);
|
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)
|
uint64_t stoull_full(const std::string & str, int base)
|
||||||
{
|
{
|
||||||
if (isspace(str[0]))
|
if (isspace(str[0]))
|
||||||
|
|
|
@ -10,6 +10,7 @@ std::string base64_decode(const std::string &in);
|
||||||
uint64_t parse_size(std::string size_str);
|
uint64_t parse_size(std::string size_str);
|
||||||
std::string strtolower(const std::string & in);
|
std::string strtolower(const std::string & in);
|
||||||
std::string trim(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);
|
uint64_t stoull_full(const std::string & str, int base = 0);
|
||||||
std::string format_size(uint64_t size, bool nobytes = false);
|
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);
|
void print_help(const char *help_text, std::string exe_name, std::string cmd, bool all);
|
||||||
|
|
Loading…
Reference in New Issue