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