- ``ceph osd reweightn`` will specify the `reweight` values for
multiple OSDs in a single command. This is equivalent to a series of
``ceph osd reweight`` commands.
- - ``ceph crush class {create,rm,ls,rename}`` manage the new CRUSH *device
- class* feature. ``ceph crush set-device-class <osd> <class>``
- will set the class for a particular device.
+ - ``ceph osd crush class {create,rm,ls,rename}`` manage the new
+ CRUSH *device class* feature. ``ceph crush set-device-class
+ <osd> <class>`` will set the class for a particular device.
+ - ``ceph osd crush rule create-replicated`` replaces the old
+ ``ceph osd crush rule create-simple`` command to create a CRUSH
+ rule for a replicated pool. Notably it takes a `class` argument
+ for the *device class* the rule should target (e.g., `ssd` or
+ `hdd`).
- ``ceph mon feature ls`` will list monitor features recorded in the
MonMap. ``ceph mon feature set`` will set an optional feature (none of
these exist yet).
ceph osd crush rule create-simple foo default host
ceph osd crush rule create-simple bar default host
+ceph osd crush class create ssd
+ceph osd crush class create hdd
+ceph osd crush set-device-class osd.0 ssd
+ceph osd crush set-device-class osd.1 hdd
+ceph osd crush rule create-replicated foo-ssd default host ssd
+ceph osd crush rule create-replicated foo-hdd default host hdd
+
ceph osd crush rule ls | grep foo
ceph osd crush rule rm foo
int CrushWrapper::add_simple_rule_at(
string name, string root_name,
string failure_domain_name,
+ string device_class,
string mode, int rule_type,
- int rno, ostream *err)
+ int rno,
+ ostream *err)
{
if (rule_exists(name)) {
if (err)
return -EINVAL;
}
}
+ if (device_class.size()) {
+ if (!class_exists(device_class)) {
+ if (err)
+ *err << "device class " << device_class << " does not exist";
+ return -EINVAL;
+ }
+ int c = get_class_id(device_class);
+ if (class_bucket.count(root) == 0 ||
+ class_bucket[root].count(c) == 0) {
+ if (err)
+ *err << "root " << root_name << " has no devices with class "
+ << device_class;
+ return -EINVAL;
+ }
+ root = class_bucket[root][c];
+ }
if (mode != "firstn" && mode != "indep") {
if (err)
*err << "unknown mode " << mode;
int CrushWrapper::add_simple_rule(
string name, string root_name,
string failure_domain_name,
+ string device_class,
string mode, int rule_type,
ostream *err)
{
- return add_simple_rule_at(name, root_name, failure_domain_name, mode,
+ return add_simple_rule_at(name, root_name, failure_domain_name, device_class,
+ mode,
rule_type, -1, err);
}
int add_simple_rule(
string name, string root_name, string failure_domain_type,
+ string device_class,
string mode, int rule_type, ostream *err = 0);
/**
*/
int add_simple_rule_at(
string name, string root_name,
- string failure_domain_type, string mode,
+ string failure_domain_type, string device_class, string mode,
int rule_type, int rno, ostream *err = 0);
int remove_rule(int ruleno);
name,
ruleset_root,
ruleset_failure_domain,
+ "",
"indep",
pg_pool_t::TYPE_ERASURE,
ss);
ostream *ss) const
{
int ruleid = crush.add_simple_rule(
- name, ruleset_root, ruleset_failure_domain,
+ name, ruleset_root, ruleset_failure_domain, "",
"indep", pg_pool_t::TYPE_ERASURE, ss);
if (ruleid < 0)
return ruleid;
ostream *ss) const
{
int ruleid = crush.add_simple_rule(
- name, ruleset_root, ruleset_failure_domain,
+ name, ruleset_root, ruleset_failure_domain, "",
"indep", pg_pool_t::TYPE_ERASURE, ss);
if (ruleid < 0) {
return ruleid;
"name=mode,type=CephChoices,strings=firstn|indep,req=false",
"create crush rule <name> to start from <root>, replicate across buckets of type <type>, using a choose mode of <firstn|indep> (default firstn; indep best for erasure pools)", \
"osd", "rw", "cli,rest")
+COMMAND("osd crush rule create-replicated " \
+ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \
+ "name=root,type=CephString,goodchars=[A-Za-z0-9-_.] " \
+ "name=type,type=CephString,goodchars=[A-Za-z0-9-_.] " \
+ "name=class,type=CephString,goodchars=[A-Za-z0-9-_.],req=false",
+ "create crush rule <name> for replicated pool to start from <root>, replicate across buckets of type <type>, using a choose mode of <firstn|indep> (default firstn; indep best for erasure pools)", \
+ "osd", "rw", "cli,rest")
COMMAND("osd crush rule create-erasure " \
"name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \
"name=profile,type=CephString,req=false,goodchars=[A-Za-z0-9-_.=]", \
ss << "rule " << name << " already exists";
err = 0;
} else {
- int ruleno = newcrush.add_simple_rule(name, root, type, mode,
+ int ruleno = newcrush.add_simple_rule(name, root, type, "", mode,
pg_pool_t::TYPE_REPLICATED, &ss);
if (ruleno < 0) {
err = ruleno;
get_last_committed() + 1));
return true;
+ } else if (prefix == "osd crush rule create-replicated") {
+ string name, root, type, device_class;
+ cmd_getval(g_ceph_context, cmdmap, "name", name);
+ cmd_getval(g_ceph_context, cmdmap, "root", root);
+ cmd_getval(g_ceph_context, cmdmap, "type", type);
+ cmd_getval(g_ceph_context, cmdmap, "class", device_class);
+
+ if (osdmap.crush->rule_exists(name)) {
+ // The name is uniquely associated to a ruleid and the rule it contains
+ // From the user point of view, the rule is more meaningfull.
+ ss << "rule " << name << " already exists";
+ err = 0;
+ goto reply;
+ }
+
+ CrushWrapper newcrush;
+ _get_pending_crush(newcrush);
+
+ if (newcrush.rule_exists(name)) {
+ // The name is uniquely associated to a ruleid and the rule it contains
+ // From the user point of view, the rule is more meaningfull.
+ ss << "rule " << name << " already exists";
+ err = 0;
+ } else {
+ int ruleno = newcrush.add_simple_rule(
+ name, root, type, device_class,
+ "firstn", pg_pool_t::TYPE_REPLICATED, &ss);
+ if (ruleno < 0) {
+ err = ruleno;
+ goto reply;
+ }
+
+ pending_inc.crush.clear();
+ newcrush.encode(pending_inc.crush, mon->get_quorum_con_features());
+ }
+ getline(ss, rs);
+ wait_for_finished_proposal(op, new Monitor::C_Command(mon, op, 0, rs,
+ get_last_committed() + 1));
+ return true;
+
} else if (prefix == "osd erasure-code-profile rm") {
string name;
cmd_getval(g_ceph_context, cmdmap, "name", name);
int r;
r = crush.add_simple_rule_at(
- "replicated_rule", root, failure_domain,
+ "replicated_rule", root, failure_domain, "",
"firstn", pg_pool_t::TYPE_REPLICATED,
crush_rule, ss);
if (r < 0)
create crush rule <name> to start from <root>,
replicate across buckets of type <type>, using
a choose mode of <firstn|indep>
+ -i mapfn --create-replicated-rule name root type
+ create crush rule <name> to start from <root>,
+ replicate across buckets of type <type>
+ --device-class <class>
+ use device class <class> for new rule
-i mapfn --remove-rule name
remove the specified crush rule
--- /dev/null
+ $ crushtool -c $TESTDIR/rules.txt --create-replicated-rule foo default host -o one > /dev/null
+ $ crushtool -d one
+ # begin crush map
+
+ # devices
+ device 0 osd.0 class ssd
+ device 1 osd.1 class ssd
+ device 2 osd.2 class ssd
+ device 3 osd.3 class hdd
+ device 4 osd.4 class hdd
+ device 5 osd.5 class hdd
+
+ # types
+ type 0 osd
+ type 1 host
+ type 2 root
+
+ # buckets
+ host foo {
+ \tid -3\t\t# do not change unnecessarily (esc)
+ \tid -4 class ssd\t\t# do not change unnecessarily (esc)
+ \tid -7 class hdd\t\t# do not change unnecessarily (esc)
+ \t# weight 3.000 (esc)
+ \talg straw2 (esc)
+ \thash 0\t# rjenkins1 (esc)
+ \titem osd.0 weight 1.000 (esc)
+ \titem osd.1 weight 1.000 (esc)
+ \titem osd.2 weight 1.000 (esc)
+ }
+ host bar {
+ \tid -2\t\t# do not change unnecessarily (esc)
+ \tid -5 class ssd\t\t# do not change unnecessarily (esc)
+ \tid -8 class hdd\t\t# do not change unnecessarily (esc)
+ \t# weight 3.000 (esc)
+ \talg straw2 (esc)
+ \thash 0\t# rjenkins1 (esc)
+ \titem osd.3 weight 1.000 (esc)
+ \titem osd.4 weight 1.000 (esc)
+ \titem osd.5 weight 1.000 (esc)
+ }
+ root default {
+ \tid -1\t\t# do not change unnecessarily (esc)
+ \tid -6 class ssd\t\t# do not change unnecessarily (esc)
+ \tid -9 class hdd\t\t# do not change unnecessarily (esc)
+ \t# weight 6.000 (esc)
+ \talg straw2 (esc)
+ \thash 0\t# rjenkins1 (esc)
+ \titem foo weight 3.000 (esc)
+ \titem bar weight 3.000 (esc)
+ }
+
+ # rules
+ rule data {
+ \truleset 0 (esc)
+ \ttype replicated (esc)
+ \tmin_size 1 (esc)
+ \tmax_size 10 (esc)
+ \tstep take default (esc)
+ \tstep chooseleaf firstn 0 type host (esc)
+ \tstep emit (esc)
+ }
+ rule foo {
+ \truleset 1 (esc)
+ \ttype replicated (esc)
+ \tmin_size 1 (esc)
+ \tmax_size 10 (esc)
+ \tstep take default (esc)
+ \tstep chooseleaf firstn 0 type host (esc)
+ \tstep emit (esc)
+ }
+
+ # end crush map
+
+
+
+
+
+ $ crushtool -c $TESTDIR/rules.txt --create-replicated-rule foo-ssd default host -o two --device-class ssd > /dev/null
+ $ crushtool -d two
+ # begin crush map
+
+ # devices
+ device 0 osd.0 class ssd
+ device 1 osd.1 class ssd
+ device 2 osd.2 class ssd
+ device 3 osd.3 class hdd
+ device 4 osd.4 class hdd
+ device 5 osd.5 class hdd
+
+ # types
+ type 0 osd
+ type 1 host
+ type 2 root
+
+ # buckets
+ host foo {
+ \tid -3\t\t# do not change unnecessarily (esc)
+ \tid -4 class ssd\t\t# do not change unnecessarily (esc)
+ \tid -7 class hdd\t\t# do not change unnecessarily (esc)
+ \t# weight 3.000 (esc)
+ \talg straw2 (esc)
+ \thash 0\t# rjenkins1 (esc)
+ \titem osd.0 weight 1.000 (esc)
+ \titem osd.1 weight 1.000 (esc)
+ \titem osd.2 weight 1.000 (esc)
+ }
+ host bar {
+ \tid -2\t\t# do not change unnecessarily (esc)
+ \tid -5 class ssd\t\t# do not change unnecessarily (esc)
+ \tid -8 class hdd\t\t# do not change unnecessarily (esc)
+ \t# weight 3.000 (esc)
+ \talg straw2 (esc)
+ \thash 0\t# rjenkins1 (esc)
+ \titem osd.3 weight 1.000 (esc)
+ \titem osd.4 weight 1.000 (esc)
+ \titem osd.5 weight 1.000 (esc)
+ }
+ root default {
+ \tid -1\t\t# do not change unnecessarily (esc)
+ \tid -6 class ssd\t\t# do not change unnecessarily (esc)
+ \tid -9 class hdd\t\t# do not change unnecessarily (esc)
+ \t# weight 6.000 (esc)
+ \talg straw2 (esc)
+ \thash 0\t# rjenkins1 (esc)
+ \titem foo weight 3.000 (esc)
+ \titem bar weight 3.000 (esc)
+ }
+
+ # rules
+ rule data {
+ \truleset 0 (esc)
+ \ttype replicated (esc)
+ \tmin_size 1 (esc)
+ \tmax_size 10 (esc)
+ \tstep take default (esc)
+ \tstep chooseleaf firstn 0 type host (esc)
+ \tstep emit (esc)
+ }
+ rule foo-ssd {
+ \truleset 1 (esc)
+ \ttype replicated (esc)
+ \tmin_size 1 (esc)
+ \tmax_size 10 (esc)
+ \tstep take default class ssd (esc)
+ \tstep chooseleaf firstn 0 type host (esc)
+ \tstep emit (esc)
+ }
+
+ # end crush map
--- /dev/null
+# begin crush map
+
+# devices
+device 0 osd.0 class ssd
+device 1 osd.1 class ssd
+device 2 osd.2 class ssd
+device 3 osd.3 class hdd
+device 4 osd.4 class hdd
+device 5 osd.5 class hdd
+
+# types
+type 0 osd
+type 1 host
+type 2 root
+
+# buckets
+host foo {
+ id -3
+ alg straw2
+ hash 0
+ item osd.0 weight 1.0
+ item osd.1 weight 1.0
+ item osd.2 weight 1.0
+}
+
+host bar {
+ id -2
+ alg straw2
+ hash 0
+ item osd.3 weight 1.0
+ item osd.4 weight 1.0
+ item osd.5 weight 1.0
+}
+
+root default {
+ id -1
+ alg straw2
+ hash 0
+ item foo weight 3.0
+ item bar weight 3.0
+}
+
+# rules
+rule data {
+ ruleset 0
+ type replicated
+ min_size 1
+ max_size 10
+ step take default
+ step chooseleaf firstn 0 type host
+ step emit
+}
+
+# end crush map
}
string name("NAME");
- int rule = c->add_simple_rule(name, root_name, failure_domain_type,
+ int rule = c->add_simple_rule(name, root_name, failure_domain_type, "",
"firstn", pg_pool_t::TYPE_ERASURE);
EXPECT_EQ(0, rule);
item = 2;
c.insert_item(g_ceph_context, item, weight, "osd.2", loc);
- assert(c.add_simple_rule("rule1", "r11", "host", "firstn", pg_pool_t::TYPE_ERASURE) >= 0);
+ assert(c.add_simple_rule("rule1", "r11", "host", "",
+ "firstn", pg_pool_t::TYPE_ERASURE) >= 0);
int id = c.get_item_id("b1");
loc["root"] = "default";
c.insert_item(g_ceph_context, item, weight, "osd.2", loc);
- assert(c.add_simple_rule("rule1", "r11", "host", "firstn", pg_pool_t::TYPE_ERASURE) >= 0);
+ assert(c.add_simple_rule("rule1", "r11", "host", "",
+ "firstn", pg_pool_t::TYPE_ERASURE) >= 0);
ASSERT_TRUE(c.name_exists("default"));
ASSERT_TRUE(c.name_exists("r11"));
ASSERT_TRUE(c.name_exists("r12"));
{
cout << "take + choose + emit" << std::endl;
ostringstream err;
- int rule = c.add_simple_rule("one", "default", "osd", "firstn", 0, &err);
+ int rule = c.add_simple_rule("one", "default", "osd", "",
+ "firstn", 0, &err);
ASSERT_EQ(rule, 0);
vector<int> orig = { 0, 3, 9 };
{
cout << "take + chooseleaf + emit" << std::endl;
ostringstream err;
- int rule = c.add_simple_rule("two", "default", "host", "firstn", 0, &err);
+ int rule = c.add_simple_rule("two", "default", "host", "",
+ "firstn", 0, &err);
ASSERT_EQ(rule, 1);
vector<int> orig = { 0, 3, 9 };
EXPECT_EQ(0, c->set_item_name(root0, root_name0));
string name0("rule0");
- int rule0 = c->add_simple_rule(name0, root_name0, "osd",
+ int rule0 = c->add_simple_rule(name0, root_name0, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
EXPECT_EQ(0, rule0);
EXPECT_EQ(0, c->set_item_name(root1, root_name1));
string name1("rule1");
- int rule1 = c->add_simple_rule(name1, root_name1, "osd",
+ int rule1 = c->add_simple_rule(name1, root_name1, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
EXPECT_EQ(1, rule1);
EXPECT_EQ(0, c->set_item_name(root0, root_name0));
string name0("rule0");
- int rule0 = c->add_simple_rule(name0, root_name0, "osd",
+ int rule0 = c->add_simple_rule(name0, root_name0, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
EXPECT_EQ(0, rule0);
EXPECT_EQ(0, c->set_item_name(root1, root_name1));
string name1("rule1");
- int rule1 = c->add_simple_rule(name1, root_name1, "osd",
+ int rule1 = c->add_simple_rule(name1, root_name1, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
EXPECT_EQ(1, rule1);
c->set_item_name(root0, root_name0);
string name0("rule0");
- int rule0 = c->add_simple_rule(name0, root_name0, "osd",
+ int rule0 = c->add_simple_rule(name0, root_name0, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
int sum[n];
EXPECT_EQ(0, c->set_item_name(root0, root_name0));
string name0("rule0");
- int rule0 = c->add_simple_rule(name0, root_name0, "osd",
+ int rule0 = c->add_simple_rule(name0, root_name0, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
EXPECT_EQ(0, rule0);
EXPECT_EQ(0, c->set_item_name(root1, root_name1));
string name1("rule1");
- int rule1 = c->add_simple_rule(name1, root_name1, "osd",
+ int rule1 = c->add_simple_rule(name1, root_name1, "osd", "",
"firstn", pg_pool_t::TYPE_REPLICATED);
EXPECT_EQ(1, rule1);
int create_ruleset(const string &name,
CrushWrapper &crush,
ostream *ss) const override {
- return crush.add_simple_rule(name, "default", "host",
+ return crush.add_simple_rule(name, "default", "host", "",
"indep", pg_pool_t::TYPE_ERASURE, ss);
}
// Create an EC ruleset and a pool using it
int r = osdmap.crush->add_simple_rule(
- "erasure", "default", "osd",
+ "erasure", "default", "osd", "",
"indep", pg_pool_t::TYPE_ERASURE,
&cerr);
<< " create crush rule <name> to start from <root>,\n"
<< " replicate across buckets of type <type>, using\n"
<< " a choose mode of <firstn|indep>\n";
+ cout << " -i mapfn --create-replicated-rule name root type\n"
+ << " create crush rule <name> to start from <root>,\n"
+ << " replicate across buckets of type <type>\n";
+ cout << " --device-class <class>\n";
+ cout << " use device class <class> for new rule\n";
cout << " -i mapfn --remove-rule name\n"
<< " remove the specified crush rule\n";
cout << "\n";
int add_item = -1;
bool update_item = false;
bool add_rule = false;
- std::string rule_name, rule_root, rule_type, rule_mode;
+ std::string rule_name, rule_root, rule_type, rule_mode, rule_device_class;
bool del_rule = false;
float add_weight = 0;
map<string,string> add_loc;
<< " mode=" << rule_mode
<< std::endl;
add_rule = true;
+ } else if (ceph_argparse_witharg(args, i, &val, err, "--create-replicated-rule", (char*)NULL)) {
+ rule_name.assign(val);
+ if (!err.str().empty()) {
+ cerr << err.str() << std::endl;
+ return EXIT_FAILURE;
+ }
+ if (i == args.end()) {
+ cerr << "expecting additional argument to --create-replicated-rule" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ rule_root.assign(*i);
+ i = args.erase(i);
+ if (i == args.end()) {
+ cerr << "expecting additional argument to --create-replicated-rule" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ rule_type.assign(*i);
+ i = args.erase(i);
+ rule_mode = "firstn";
+
+ cout << "--create-replicated-rule:"
+ << " name=" << rule_name
+ << " root=" << rule_root
+ << " type=" << rule_type
+ << std::endl;
+ add_rule = true;
+
+ } else if (ceph_argparse_witharg(args, i, &val, "--device-class", (char*)NULL)) {
+ rule_device_class.assign(val);
+ if (!err.str().empty()) {
+ cerr << err.str() << std::endl;
+ return EXIT_FAILURE;
+ }
} else if (ceph_argparse_witharg(args, i, &val, "--remove-rule", (char*)NULL)) {
rule_name.assign(val);
if (!err.str().empty()) {
cerr << "rule " << rule_name << " already exists" << std::endl;
return EXIT_FAILURE;
}
- int r = crush.add_simple_rule(rule_name, rule_root, rule_type, rule_mode,
- pg_pool_t::TYPE_REPLICATED, &err);
+ int r = crush.add_simple_rule(rule_name, rule_root, rule_type,
+ rule_device_class,
+ rule_mode, pg_pool_t::TYPE_REPLICATED, &err);
if (r < 0) {
cerr << err.str() << std::endl;
return EXIT_FAILURE;