]> git.proxmox.com Git - ceph.git/blame - ceph/src/mon/FSCommands.cc
bump version to 12.0.3-pve3
[ceph.git] / ceph / src / mon / FSCommands.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2017 Red Hat Ltd
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15
16#include "OSDMonitor.h"
17#include "PGMonitor.h"
18
19#include "FSCommands.h"
20#include "MDSMonitor.h"
21
22
23
24static const string EXPERIMENTAL_WARNING("Warning! This feature is experimental."
25"It may cause problems up to and including data loss."
26"Consult the documentation at ceph.com, and if unsure, do not proceed."
27"Add --yes-i-really-mean-it if you are certain.");
28
29
30
31class FlagSetHandler : public FileSystemCommandHandler
32{
33 public:
34 FlagSetHandler()
35 : FileSystemCommandHandler("fs flag set")
36 {
37 }
38
39 int handle(
40 Monitor *mon,
41 FSMap &fsmap,
42 MonOpRequestRef op,
43 map<string, cmd_vartype> &cmdmap,
44 std::stringstream &ss) override
45 {
46 string flag_name;
47 cmd_getval(g_ceph_context, cmdmap, "flag_name", flag_name);
48
49 string flag_val;
50 cmd_getval(g_ceph_context, cmdmap, "val", flag_val);
51
52 string confirm;
53 cmd_getval(g_ceph_context, cmdmap, "confirm", confirm);
54
55 if (flag_name == "enable_multiple") {
56 bool flag_bool = false;
57 int r = parse_bool(flag_val, &flag_bool, ss);
58 if (r != 0) {
59 ss << "Invalid boolean value '" << flag_val << "'";
60 return r;
61 }
62
63 bool jewel = mon->get_quorum_con_features() & CEPH_FEATURE_SERVER_JEWEL;
64 if (flag_bool && !jewel) {
65 ss << "Multiple-filesystems are forbidden until all mons are updated";
66 return -EINVAL;
67 }
68 if (confirm != "--yes-i-really-mean-it") {
69 ss << EXPERIMENTAL_WARNING;
70 }
71 fsmap.set_enable_multiple(flag_bool);
72 return 0;
73 } else {
74 ss << "Unknown flag '" << flag_name << "'";
75 return -EINVAL;
76 }
77 }
78};
79
80class FsNewHandler : public FileSystemCommandHandler
81{
82 public:
83 FsNewHandler()
84 : FileSystemCommandHandler("fs new")
85 {
86 }
87
88 int handle(
89 Monitor *mon,
90 FSMap &fsmap,
91 MonOpRequestRef op,
92 map<string, cmd_vartype> &cmdmap,
93 std::stringstream &ss)
94 {
95 string metadata_name;
96 cmd_getval(g_ceph_context, cmdmap, "metadata", metadata_name);
97 int64_t metadata = mon->osdmon()->osdmap.lookup_pg_pool_name(metadata_name);
98 if (metadata < 0) {
99 ss << "pool '" << metadata_name << "' does not exist";
100 return -ENOENT;
101 }
102
103 string force;
104 cmd_getval(g_ceph_context,cmdmap, "force", force);
105 int64_t metadata_num_objects = mon->pgmon()->pg_map.pg_pool_sum[metadata].stats.sum.num_objects;
106 if (force != "--force" && metadata_num_objects > 0) {
107 ss << "pool '" << metadata_name
108 << "' already contains some objects. Use an empty pool instead.";
109 return -EINVAL;
110 }
111
112 string data_name;
113 cmd_getval(g_ceph_context, cmdmap, "data", data_name);
114 int64_t data = mon->osdmon()->osdmap.lookup_pg_pool_name(data_name);
115 if (data < 0) {
116 ss << "pool '" << data_name << "' does not exist";
117 return -ENOENT;
118 }
119 if (data == 0) {
120 ss << "pool '" << data_name << "' has id 0, which CephFS does not allow. Use another pool or recreate it to get a non-zero pool id.";
121 return -EINVAL;
122 }
123
124 string fs_name;
125 cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name);
126 if (fs_name.empty()) {
127 // Ensure fs name is not empty so that we can implement
128 // commmands that refer to FS by name in future.
129 ss << "Filesystem name may not be empty";
130 return -EINVAL;
131 }
132
133 if (fsmap.get_filesystem(fs_name)) {
134 auto fs = fsmap.get_filesystem(fs_name);
135 if (*(fs->mds_map.get_data_pools().begin()) == data
136 && fs->mds_map.get_metadata_pool() == metadata) {
137 // Identical FS created already, this is a no-op
138 ss << "filesystem '" << fs_name << "' already exists";
139 return 0;
140 } else {
141 ss << "filesystem already exists with name '" << fs_name << "'";
142 return -EINVAL;
143 }
144 }
145
146 if (fsmap.filesystem_count() > 0
147 && !fsmap.get_enable_multiple()) {
148 ss << "Creation of multiple filesystems is disabled. To enable "
149 "this experimental feature, use 'ceph fs flag set enable_multiple "
150 "true'";
151 return -EINVAL;
152 }
153
154 for (auto fs : fsmap.get_filesystems()) {
155 const set<int64_t>& data_pools = fs->mds_map.get_data_pools();
156 string sure;
157 if ((data_pools.find(data) != data_pools.end()
158 || fs->mds_map.get_metadata_pool() == metadata)
159 && ((!cmd_getval(g_ceph_context, cmdmap, "sure", sure)
160 || sure != "--allow-dangerous-metadata-overlay"))) {
161 ss << "Filesystem '" << fs_name
162 << "' is already using one of the specified RADOS pools. This should ONLY be done in emergencies and after careful reading of the documentation. Pass --allow-dangerous-metadata-overlay to permit this.";
163 return -EEXIST;
164 }
165 }
166
167 pg_pool_t const *data_pool = mon->osdmon()->osdmap.get_pg_pool(data);
168 assert(data_pool != NULL); // Checked it existed above
169 pg_pool_t const *metadata_pool = mon->osdmon()->osdmap.get_pg_pool(metadata);
170 assert(metadata_pool != NULL); // Checked it existed above
171
172 // we must make these checks before we even allow ourselves to *think*
173 // about requesting a proposal to the osdmonitor and bail out now if
174 // we believe we must. bailing out *after* we request the proposal is
175 // bad business as we could have changed the osdmon's state and ending up
176 // returning an error to the user.
177 int r = _check_pool(mon->osdmon()->osdmap, data, false, &ss);
178 if (r < 0) {
179 return r;
180 }
181
182 r = _check_pool(mon->osdmon()->osdmap, metadata, true, &ss);
183 if (r < 0) {
184 return r;
185 }
186
187 // All checks passed, go ahead and create.
188 fsmap.create_filesystem(fs_name, metadata, data,
189 mon->get_quorum_con_features());
190 ss << "new fs with metadata pool " << metadata << " and data pool " << data;
191 return 0;
192 }
193};
194
195class SetHandler : public FileSystemCommandHandler
196{
197public:
198 SetHandler()
199 : FileSystemCommandHandler("fs set")
200 {}
201
202 int handle(
203 Monitor *mon,
204 FSMap &fsmap,
205 MonOpRequestRef op,
206 map<string, cmd_vartype> &cmdmap,
207 std::stringstream &ss) override
208 {
209 std::string fs_name;
210 if (!cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name) || fs_name.empty()) {
211 ss << "Missing filesystem name";
212 return -EINVAL;
213 }
214
215 auto fs = fsmap.get_filesystem(fs_name);
216 if (fs == nullptr) {
217 ss << "Not found: '" << fs_name << "'";
218 return -ENOENT;
219 }
220
221 string var;
222 if (!cmd_getval(g_ceph_context, cmdmap, "var", var) || var.empty()) {
223 ss << "Invalid variable";
224 return -EINVAL;
225 }
226 string val;
227 string interr;
228 int64_t n = 0;
229 if (!cmd_getval(g_ceph_context, cmdmap, "val", val)) {
230 return -EINVAL;
231 }
232 // we got a string. see if it contains an int.
233 n = strict_strtoll(val.c_str(), 10, &interr);
234 if (var == "max_mds") {
235 // NOTE: see also "mds set_max_mds", which can modify the same field.
236 if (interr.length()) {
237 ss << interr;
238 return -EINVAL;
239 }
240
241 if (n <= 0) {
242 ss << "You must specify at least one MDS";
243 return -EINVAL;
244 }
245
246 if (!fs->mds_map.allows_multimds() && n > fs->mds_map.get_max_mds() &&
247 n > 1) {
248 ss << "multi-MDS clusters are not enabled; set 'allow_multimds' to enable";
249 return -EINVAL;
250 }
251 if (n > MAX_MDS) {
252 ss << "may not have more than " << MAX_MDS << " MDS ranks";
253 return -EINVAL;
254 }
255 fsmap.modify_filesystem(
256 fs->fscid,
257 [n](std::shared_ptr<Filesystem> fs)
258 {
259 fs->mds_map.set_max_mds(n);
260 });
261 } else if (var == "inline_data") {
262 bool enable_inline = false;
263 int r = parse_bool(val, &enable_inline, ss);
264 if (r != 0) {
265 return r;
266 }
267
268 if (enable_inline) {
269 string confirm;
270 if (!cmd_getval(g_ceph_context, cmdmap, "confirm", confirm) ||
271 confirm != "--yes-i-really-mean-it") {
272 ss << EXPERIMENTAL_WARNING;
273 return -EPERM;
274 }
275 ss << "inline data enabled";
276
277 fsmap.modify_filesystem(
278 fs->fscid,
279 [](std::shared_ptr<Filesystem> fs)
280 {
281 fs->mds_map.set_inline_data_enabled(true);
282 });
283
284 // Update `compat`
285 CompatSet c = fsmap.get_compat();
286 c.incompat.insert(MDS_FEATURE_INCOMPAT_INLINE);
287 fsmap.update_compat(c);
288 } else {
289 ss << "inline data disabled";
290 fsmap.modify_filesystem(
291 fs->fscid,
292 [](std::shared_ptr<Filesystem> fs)
293 {
294 fs->mds_map.set_inline_data_enabled(false);
295 });
296 }
297 } else if (var == "balancer") {
298 ss << "setting the metadata load balancer to " << val;
299 fsmap.modify_filesystem(
300 fs->fscid,
301 [val](std::shared_ptr<Filesystem> fs)
302 {
303 fs->mds_map.set_balancer(val);
304 });
305 return true;
306 } else if (var == "max_file_size") {
307 if (interr.length()) {
308 ss << var << " requires an integer value";
309 return -EINVAL;
310 }
311 if (n < CEPH_MIN_STRIPE_UNIT) {
312 ss << var << " must at least " << CEPH_MIN_STRIPE_UNIT;
313 return -ERANGE;
314 }
315 fsmap.modify_filesystem(
316 fs->fscid,
317 [n](std::shared_ptr<Filesystem> fs)
318 {
319 fs->mds_map.set_max_filesize(n);
320 });
321 } else if (var == "allow_new_snaps") {
322 bool enable_snaps = false;
323 int r = parse_bool(val, &enable_snaps, ss);
324 if (r != 0) {
325 return r;
326 }
327
328 if (!enable_snaps) {
329 fsmap.modify_filesystem(
330 fs->fscid,
331 [](std::shared_ptr<Filesystem> fs)
332 {
333 fs->mds_map.clear_snaps_allowed();
334 });
335 ss << "disabled new snapshots";
336 } else {
337 string confirm;
338 if (!cmd_getval(g_ceph_context, cmdmap, "confirm", confirm) ||
339 confirm != "--yes-i-really-mean-it") {
340 ss << EXPERIMENTAL_WARNING;
341 return -EPERM;
342 }
343 fsmap.modify_filesystem(
344 fs->fscid,
345 [](std::shared_ptr<Filesystem> fs)
346 {
347 fs->mds_map.set_snaps_allowed();
348 });
349 ss << "enabled new snapshots";
350 }
351 } else if (var == "allow_multimds") {
352 bool enable_multimds = false;
353 int r = parse_bool(val, &enable_multimds, ss);
354 if (r != 0) {
355 return r;
356 }
357
358 if (!enable_multimds) {
359 fsmap.modify_filesystem(fs->fscid,
360 [](std::shared_ptr<Filesystem> fs)
361 {
362 fs->mds_map.clear_multimds_allowed();
363 });
364 ss << "disallowed increasing the cluster size past 1";
365 } else {
366 string confirm;
367 if (!cmd_getval(g_ceph_context, cmdmap, "confirm", confirm) ||
368 confirm != "--yes-i-really-mean-it") {
369 ss << EXPERIMENTAL_WARNING;
370 return -EPERM;
371 }
372 fsmap.modify_filesystem(
373 fs->fscid,
374 [](std::shared_ptr<Filesystem> fs)
375 {
376 fs->mds_map.set_multimds_allowed();
377 });
378 ss << "enabled creation of more than 1 active MDS";
379 }
380 } else if (var == "allow_dirfrags") {
381 bool enable_dirfrags = false;
382 int r = parse_bool(val, &enable_dirfrags, ss);
383 if (r != 0) {
384 return r;
385 }
386
387 if (!enable_dirfrags) {
388 fsmap.modify_filesystem(fs->fscid,
389 [](std::shared_ptr<Filesystem> fs)
390 {
391 fs->mds_map.clear_dirfrags_allowed();
392 });
393 ss << "disallowed new directory fragmentation";
394 } else {
395 fsmap.modify_filesystem(
396 fs->fscid,
397 [](std::shared_ptr<Filesystem> fs)
398 {
399 fs->mds_map.set_dirfrags_allowed();
400 });
401 ss << "enabled directory fragmentation";
402 }
403 } else if (var == "cluster_down") {
404 bool is_down = false;
405 int r = parse_bool(val, &is_down, ss);
406 if (r != 0) {
407 return r;
408 }
409
410 fsmap.modify_filesystem(
411 fs->fscid,
412 [is_down](std::shared_ptr<Filesystem> fs)
413 {
414 if (is_down) {
415 fs->mds_map.set_flag(CEPH_MDSMAP_DOWN);
416 } else {
417 fs->mds_map.clear_flag(CEPH_MDSMAP_DOWN);
418 }
419 });
420
421 ss << "marked " << (is_down ? "down" : "up");
422 } else if (var == "standby_count_wanted") {
423 if (interr.length()) {
424 ss << var << " requires an integer value";
425 return -EINVAL;
426 }
427 if (n < 0) {
428 ss << var << " must be non-negative";
429 return -ERANGE;
430 }
431 fsmap.modify_filesystem(
432 fs->fscid,
433 [n](std::shared_ptr<Filesystem> fs)
434 {
435 fs->mds_map.set_standby_count_wanted(n);
436 });
437 } else {
438 ss << "unknown variable " << var;
439 return -EINVAL;
440 }
441
442 return 0;
443 }
444};
445
446class AddDataPoolHandler : public FileSystemCommandHandler
447{
448 public:
449 AddDataPoolHandler()
450 : FileSystemCommandHandler("fs add_data_pool")
451 {}
452
453 int handle(
454 Monitor *mon,
455 FSMap &fsmap,
456 MonOpRequestRef op,
457 map<string, cmd_vartype> &cmdmap,
458 std::stringstream &ss) override
459 {
460 string poolname;
461 cmd_getval(g_ceph_context, cmdmap, "pool", poolname);
462
463 std::string fs_name;
464 if (!cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name)
465 || fs_name.empty()) {
466 ss << "Missing filesystem name";
467 return -EINVAL;
468 }
469
470 auto fs = fsmap.get_filesystem(fs_name);
471 if (fs == nullptr) {
472 ss << "Not found: '" << fs_name << "'";
473 return -ENOENT;
474 }
475
476 int64_t poolid = mon->osdmon()->osdmap.lookup_pg_pool_name(poolname);
477 if (poolid < 0) {
478 string err;
479 poolid = strict_strtol(poolname.c_str(), 10, &err);
480 if (err.length()) {
481 ss << "pool '" << poolname << "' does not exist";
482 return -ENOENT;
483 }
484 }
485
486 int r = _check_pool(mon->osdmon()->osdmap, poolid, false, &ss);
487 if (r != 0) {
488 return r;
489 }
490
491 fsmap.modify_filesystem(
492 fs->fscid,
493 [poolid](std::shared_ptr<Filesystem> fs)
494 {
495 fs->mds_map.add_data_pool(poolid);
496 });
497
498 ss << "added data pool " << poolid << " to fsmap";
499
500 return 0;
501 }
502};
503
504class SetDefaultHandler : public FileSystemCommandHandler
505{
506 public:
507 SetDefaultHandler()
508 : FileSystemCommandHandler("fs set-default")
509 {}
510
511 int handle(
512 Monitor *mon,
513 FSMap &fsmap,
514 MonOpRequestRef op,
515 map<string, cmd_vartype> &cmdmap,
516 std::stringstream &ss) override
517 {
518 std::string fs_name;
519 cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name);
520 auto fs = fsmap.get_filesystem(fs_name);
521 if (fs == nullptr) {
522 ss << "filesystem '" << fs_name << "' does not exist";
523 return -ENOENT;
524 }
525
526 fsmap.set_legacy_client_fscid(fs->fscid);
527 return 0;
528 }
529};
530
531class RemoveFilesystemHandler : public FileSystemCommandHandler
532{
533 public:
534 RemoveFilesystemHandler()
535 : FileSystemCommandHandler("fs rm")
536 {}
537
538 int handle(
539 Monitor *mon,
540 FSMap &fsmap,
541 MonOpRequestRef op,
542 map<string, cmd_vartype> &cmdmap,
543 std::stringstream &ss) override
544 {
545 // Check caller has correctly named the FS to delete
546 // (redundant while there is only one FS, but command
547 // syntax should apply to multi-FS future)
548 string fs_name;
549 cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name);
550 auto fs = fsmap.get_filesystem(fs_name);
551 if (fs == nullptr) {
552 // Consider absence success to make deletes idempotent
553 ss << "filesystem '" << fs_name << "' does not exist";
554 return 0;
555 }
556
557 // Check that no MDS daemons are active
558 if (fs->mds_map.get_num_up_mds() > 0) {
559 ss << "all MDS daemons must be inactive before removing filesystem";
560 return -EINVAL;
561 }
562
563 // Check for confirmation flag
564 string sure;
565 cmd_getval(g_ceph_context, cmdmap, "sure", sure);
566 if (sure != "--yes-i-really-mean-it") {
567 ss << "this is a DESTRUCTIVE operation and will make data in your filesystem permanently" \
568 " inaccessible. Add --yes-i-really-mean-it if you are sure you wish to continue.";
569 return -EPERM;
570 }
571
572 if (fsmap.get_legacy_client_fscid() == fs->fscid) {
573 fsmap.set_legacy_client_fscid(FS_CLUSTER_ID_NONE);
574 }
575
576 std::vector<mds_gid_t> to_fail;
577 // There may be standby_replay daemons left here
578 for (const auto &i : fs->mds_map.get_mds_info()) {
579 assert(i.second.state == MDSMap::STATE_STANDBY_REPLAY);
580 to_fail.push_back(i.first);
581 }
582
583 for (const auto &gid : to_fail) {
584 // Standby replays don't write, so it isn't important to
585 // wait for an osdmap propose here: ignore return value.
586 mon->mdsmon()->fail_mds_gid(gid);
587 }
588
589 fsmap.erase_filesystem(fs->fscid);
590
591 return 0;
592 }
593};
594
595class ResetFilesystemHandler : public FileSystemCommandHandler
596{
597 public:
598 ResetFilesystemHandler()
599 : FileSystemCommandHandler("fs reset")
600 {}
601
602 int handle(
603 Monitor *mon,
604 FSMap &fsmap,
605 MonOpRequestRef op,
606 map<string, cmd_vartype> &cmdmap,
607 std::stringstream &ss) override
608 {
609 string fs_name;
610 cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name);
611 auto fs = fsmap.get_filesystem(fs_name);
612 if (fs == nullptr) {
613 ss << "filesystem '" << fs_name << "' does not exist";
614 // Unlike fs rm, we consider this case an error
615 return -ENOENT;
616 }
617
618 // Check that no MDS daemons are active
619 if (fs->mds_map.get_num_up_mds() > 0) {
620 ss << "all MDS daemons must be inactive before resetting filesystem: set the cluster_down flag"
621 " and use `ceph mds fail` to make this so";
622 return -EINVAL;
623 }
624
625 // Check for confirmation flag
626 string sure;
627 cmd_getval(g_ceph_context, cmdmap, "sure", sure);
628 if (sure != "--yes-i-really-mean-it") {
629 ss << "this is a potentially destructive operation, only for use by experts in disaster recovery. "
630 "Add --yes-i-really-mean-it if you are sure you wish to continue.";
631 return -EPERM;
632 }
633
634 fsmap.reset_filesystem(fs->fscid);
635
636 return 0;
637 }
638};
639
640class RemoveDataPoolHandler : public FileSystemCommandHandler
641{
642 public:
643 RemoveDataPoolHandler()
644 : FileSystemCommandHandler("fs rm_data_pool")
645 {}
646
647 int handle(
648 Monitor *mon,
649 FSMap &fsmap,
650 MonOpRequestRef op,
651 map<string, cmd_vartype> &cmdmap,
652 std::stringstream &ss) override
653 {
654 string poolname;
655 cmd_getval(g_ceph_context, cmdmap, "pool", poolname);
656
657 std::string fs_name;
658 if (!cmd_getval(g_ceph_context, cmdmap, "fs_name", fs_name)
659 || fs_name.empty()) {
660 ss << "Missing filesystem name";
661 return -EINVAL;
662 }
663
664 auto fs = fsmap.get_filesystem(fs_name);
665 if (fs == nullptr) {
666 ss << "Not found: '" << fs_name << "'";
667 return -ENOENT;
668 }
669
670 int64_t poolid = mon->osdmon()->osdmap.lookup_pg_pool_name(poolname);
671 if (poolid < 0) {
672 string err;
673 poolid = strict_strtol(poolname.c_str(), 10, &err);
674 if (err.length()) {
675 ss << "pool '" << poolname << "' does not exist";
676 return -ENOENT;
677 } else if (poolid < 0) {
678 ss << "invalid pool id '" << poolid << "'";
679 return -EINVAL;
680 }
681 }
682
683 assert(poolid >= 0); // Checked by parsing code above
684
685 if (fs->mds_map.get_first_data_pool() == poolid) {
686 ss << "cannot remove default data pool";
687 return -EINVAL;
688 }
689
690
691 int r = 0;
692 fsmap.modify_filesystem(fs->fscid,
693 [&r, poolid](std::shared_ptr<Filesystem> fs)
694 {
695 r = fs->mds_map.remove_data_pool(poolid);
696 });
697 if (r == -ENOENT) {
698 // It was already removed, succeed in silence
699 return 0;
700 } else if (r == 0) {
701 // We removed it, succeed
702 ss << "removed data pool " << poolid << " from fsmap";
703 return 0;
704 } else {
705 // Unexpected error, bubble up
706 return r;
707 }
708 }
709};
710
711
712/**
713 * For commands that refer to a particular filesystem,
714 * enable wrapping to implement the legacy version of
715 * the command (like "mds add_data_pool" vs "fs add_data_pool")
716 *
717 * The wrapped handler must expect a fs_name argument in
718 * its command map.
719 */
720template<typename T>
721class LegacyHandler : public T
722{
723 std::string legacy_prefix;
724
725 public:
726 LegacyHandler(const std::string &new_prefix)
727 : T()
728 {
729 legacy_prefix = new_prefix;
730 }
731
732 std::string const &get_prefix() override {return legacy_prefix;}
733
734 int handle(
735 Monitor *mon,
736 FSMap &fsmap,
737 MonOpRequestRef op,
738 map<string, cmd_vartype> &cmdmap,
739 std::stringstream &ss) override
740 {
741 auto fs = fsmap.get_legacy_filesystem();
742 if (fs == nullptr) {
743 ss << "No filesystem configured";
744 return -ENOENT;
745 }
746 std::map<string, cmd_vartype> modified = cmdmap;
747 modified["fs_name"] = fs->mds_map.get_fs_name();
748 return T::handle(mon, fsmap, op, modified, ss);
749 }
750};
751
752/**
753 * For commands with an alternative prefix
754 */
755template<typename T>
756class AliasHandler : public T
757{
758 std::string alias_prefix;
759
760 public:
761 AliasHandler(const std::string &new_prefix)
762 : T()
763 {
764 alias_prefix = new_prefix;
765 }
766
767 std::string const &get_prefix() override {return alias_prefix;}
768
769 int handle(
770 Monitor *mon,
771 FSMap &fsmap,
772 MonOpRequestRef op,
773 map<string, cmd_vartype> &cmdmap,
774 std::stringstream &ss) override
775 {
776 return T::handle(mon, fsmap, op, cmdmap, ss);
777 }
778};
779
780
781std::list<std::shared_ptr<FileSystemCommandHandler> > FileSystemCommandHandler::load()
782{
783 std::list<std::shared_ptr<FileSystemCommandHandler> > handlers;
784
785 handlers.push_back(std::make_shared<SetHandler>());
786 handlers.push_back(std::make_shared<LegacyHandler<SetHandler> >("mds set"));
787 handlers.push_back(std::make_shared<FlagSetHandler>());
788 handlers.push_back(std::make_shared<AddDataPoolHandler>());
789 handlers.push_back(std::make_shared<LegacyHandler<AddDataPoolHandler> >(
790 "mds add_data_pool"));
791 handlers.push_back(std::make_shared<RemoveDataPoolHandler>());
792 handlers.push_back(std::make_shared<LegacyHandler<RemoveDataPoolHandler> >(
793 "mds remove_data_pool"));
794 handlers.push_back(std::make_shared<LegacyHandler<RemoveDataPoolHandler> >(
795 "mds rm_data_pool"));
796 handlers.push_back(std::make_shared<FsNewHandler>());
797 handlers.push_back(std::make_shared<RemoveFilesystemHandler>());
798 handlers.push_back(std::make_shared<ResetFilesystemHandler>());
799
800 handlers.push_back(std::make_shared<SetDefaultHandler>());
801 handlers.push_back(std::make_shared<AliasHandler<SetDefaultHandler> >(
802 "fs set_default"));
803
804 return handlers;
805}
806
807int FileSystemCommandHandler::parse_bool(
808 const std::string &bool_str,
809 bool *result,
810 std::ostream &ss)
811{
812 assert(result != nullptr);
813
814 string interr;
815 int64_t n = strict_strtoll(bool_str.c_str(), 10, &interr);
816
817 if (bool_str == "false" || bool_str == "no"
818 || (interr.length() == 0 && n == 0)) {
819 *result = false;
820 return 0;
821 } else if (bool_str == "true" || bool_str == "yes"
822 || (interr.length() == 0 && n == 1)) {
823 *result = true;
824 return 0;
825 } else {
826 ss << "value must be false|no|0 or true|yes|1";
827 return -EINVAL;
828 }
829}
830
831int FileSystemCommandHandler::_check_pool(
832 OSDMap &osd_map,
833 const int64_t pool_id,
834 bool metadata,
835 std::stringstream *ss) const
836{
837 assert(ss != NULL);
838
839 const pg_pool_t *pool = osd_map.get_pg_pool(pool_id);
840 if (!pool) {
841 *ss << "pool id '" << pool_id << "' does not exist";
842 return -ENOENT;
843 }
844
845 const string& pool_name = osd_map.get_pool_name(pool_id);
846
847 if (pool->is_erasure() && metadata) {
848 *ss << "pool '" << pool_name << "' (id '" << pool_id << "')"
849 << " is an erasure-coded pool. Use of erasure-coded pools"
850 << " for CephFS metadata is not permitted";
851 return -EINVAL;
852 } else if (pool->is_erasure() && !pool->allows_ecoverwrites()) {
853 // non-overwriteable EC pools are only acceptable with a cache tier overlay
854 if (!pool->has_tiers() || !pool->has_read_tier() || !pool->has_write_tier()) {
855 *ss << "pool '" << pool_name << "' (id '" << pool_id << "')"
856 << " is an erasure-coded pool, with no overwrite support";
857 return -EINVAL;
858 }
859
860 // That cache tier overlay must be writeback, not readonly (it's the
861 // write operations like modify+truncate we care about support for)
862 const pg_pool_t *write_tier = osd_map.get_pg_pool(
863 pool->write_tier);
864 assert(write_tier != NULL); // OSDMonitor shouldn't allow DNE tier
865 if (write_tier->cache_mode == pg_pool_t::CACHEMODE_FORWARD
866 || write_tier->cache_mode == pg_pool_t::CACHEMODE_READONLY) {
867 *ss << "EC pool '" << pool_name << "' has a write tier ("
868 << osd_map.get_pool_name(pool->write_tier)
869 << ") that is configured "
870 "to forward writes. Use a cache mode such as 'writeback' for "
871 "CephFS";
872 return -EINVAL;
873 }
874 }
875
876 if (pool->is_tier()) {
877 *ss << " pool '" << pool_name << "' (id '" << pool_id
878 << "') is already in use as a cache tier.";
879 return -EINVAL;
880 }
881
882 // Nothing special about this pool, so it is permissible
883 return 0;
884}
885