1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2017 Red Hat Ltd
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.
16 #include "OSDMonitor.h"
18 #include "FSCommands.h"
19 #include "MDSMonitor.h"
20 #include "MgrStatMonitor.h"
23 static const string
EXPERIMENTAL_WARNING("Warning! This feature is experimental."
24 "It may cause problems up to and including data loss."
25 "Consult the documentation at ceph.com, and if unsure, do not proceed."
26 "Add --yes-i-really-mean-it if you are certain.");
30 class FlagSetHandler
: public FileSystemCommandHandler
34 : FileSystemCommandHandler("fs flag set")
42 const cmdmap_t
& cmdmap
,
43 std::stringstream
&ss
) override
46 cmd_getval(g_ceph_context
, cmdmap
, "flag_name", flag_name
);
49 cmd_getval(g_ceph_context
, cmdmap
, "val", flag_val
);
52 cmd_getval(g_ceph_context
, cmdmap
, "yes_i_really_mean_it", sure
);
54 if (flag_name
== "enable_multiple") {
55 bool flag_bool
= false;
56 int r
= parse_bool(flag_val
, &flag_bool
, ss
);
58 ss
<< "Invalid boolean value '" << flag_val
<< "'";
62 bool jewel
= mon
->get_quorum_con_features() & CEPH_FEATURE_SERVER_JEWEL
;
63 if (flag_bool
&& !jewel
) {
64 ss
<< "Multiple-filesystems are forbidden until all mons are updated";
68 ss
<< EXPERIMENTAL_WARNING
;
70 fsmap
.set_enable_multiple(flag_bool
);
73 ss
<< "Unknown flag '" << flag_name
<< "'";
79 class FailHandler
: public FileSystemCommandHandler
83 : FileSystemCommandHandler("fs fail")
91 const cmdmap_t
& cmdmap
,
92 std::stringstream
& ss
) override
94 if (!mon
->osdmon()->is_writeable()) {
95 // not allowed to write yet, so retry when we can
96 mon
->osdmon()->wait_for_writeable(op
, new PaxosService::C_RetryMessage(mon
->mdsmon(), op
));
101 if (!cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
) || fs_name
.empty()) {
102 ss
<< "Missing filesystem name";
106 auto fs
= fsmap
.get_filesystem(fs_name
);
108 ss
<< "Not found: '" << fs_name
<< "'";
112 auto f
= [](auto fs
) {
113 fs
->mds_map
.set_flag(CEPH_MDSMAP_NOT_JOINABLE
);
115 fsmap
.modify_filesystem(fs
->fscid
, std::move(f
));
117 std::vector
<mds_gid_t
> to_fail
;
118 for (const auto& p
: fs
->mds_map
.get_mds_info()) {
119 to_fail
.push_back(p
.first
);
122 for (const auto& gid
: to_fail
) {
123 mon
->mdsmon()->fail_mds_gid(fsmap
, gid
);
125 if (!to_fail
.empty()) {
126 mon
->osdmon()->propose_pending();
130 ss
<< " marked not joinable; MDS cannot join the cluster. All MDS ranks marked failed.";
136 class FsNewHandler
: public FileSystemCommandHandler
139 explicit FsNewHandler(Paxos
*paxos
)
140 : FileSystemCommandHandler("fs new"), m_paxos(paxos
)
144 bool batched_propose() override
{
152 const cmdmap_t
& cmdmap
,
153 std::stringstream
&ss
) override
155 ceph_assert(m_paxos
->is_plugged());
157 string metadata_name
;
158 cmd_getval(g_ceph_context
, cmdmap
, "metadata", metadata_name
);
159 int64_t metadata
= mon
->osdmon()->osdmap
.lookup_pg_pool_name(metadata_name
);
161 ss
<< "pool '" << metadata_name
<< "' does not exist";
166 cmd_getval(g_ceph_context
, cmdmap
, "data", data_name
);
167 int64_t data
= mon
->osdmon()->osdmap
.lookup_pg_pool_name(data_name
);
169 ss
<< "pool '" << data_name
<< "' does not exist";
173 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.";
178 cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
);
179 if (fs_name
.empty()) {
180 // Ensure fs name is not empty so that we can implement
181 // commmands that refer to FS by name in future.
182 ss
<< "Filesystem name may not be empty";
186 if (fsmap
.get_filesystem(fs_name
)) {
187 auto fs
= fsmap
.get_filesystem(fs_name
);
188 if (*(fs
->mds_map
.get_data_pools().begin()) == data
189 && fs
->mds_map
.get_metadata_pool() == metadata
) {
190 // Identical FS created already, this is a no-op
191 ss
<< "filesystem '" << fs_name
<< "' already exists";
194 ss
<< "filesystem already exists with name '" << fs_name
<< "'";
200 cmd_getval(g_ceph_context
,cmdmap
, "force", force
);
202 const pool_stat_t
*stat
= mon
->mgrstatmon()->get_pool_stat(metadata
);
204 int64_t metadata_num_objects
= stat
->stats
.sum
.num_objects
;
205 if (!force
&& metadata_num_objects
> 0) {
206 ss
<< "pool '" << metadata_name
207 << "' already contains some objects. Use an empty pool instead.";
212 if (fsmap
.filesystem_count() > 0
213 && !fsmap
.get_enable_multiple()) {
214 ss
<< "Creation of multiple filesystems is disabled. To enable "
215 "this experimental feature, use 'ceph fs flag set enable_multiple "
220 for (auto& fs
: fsmap
.get_filesystems()) {
221 const std::vector
<int64_t> &data_pools
= fs
->mds_map
.get_data_pools();
224 cmd_getval(g_ceph_context
, cmdmap
,
225 "allow_dangerous_metadata_overlay", sure
);
227 if ((std::find(data_pools
.begin(), data_pools
.end(), data
) != data_pools
.end()
228 || fs
->mds_map
.get_metadata_pool() == metadata
)
230 ss
<< "Filesystem '" << fs_name
231 << "' 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.";
236 pg_pool_t
const *data_pool
= mon
->osdmon()->osdmap
.get_pg_pool(data
);
237 ceph_assert(data_pool
!= NULL
); // Checked it existed above
238 pg_pool_t
const *metadata_pool
= mon
->osdmon()->osdmap
.get_pg_pool(metadata
);
239 ceph_assert(metadata_pool
!= NULL
); // Checked it existed above
241 int r
= _check_pool(mon
->osdmon()->osdmap
, data
, POOL_DATA_DEFAULT
, force
, &ss
);
246 r
= _check_pool(mon
->osdmon()->osdmap
, metadata
, POOL_METADATA
, force
, &ss
);
251 if (!mon
->osdmon()->is_writeable()) {
252 // not allowed to write yet, so retry when we can
253 mon
->osdmon()->wait_for_writeable(op
, new PaxosService::C_RetryMessage(mon
->mdsmon(), op
));
256 mon
->osdmon()->do_application_enable(data
,
257 pg_pool_t::APPLICATION_NAME_CEPHFS
,
259 mon
->osdmon()->do_application_enable(metadata
,
260 pg_pool_t::APPLICATION_NAME_CEPHFS
,
261 "metadata", fs_name
);
262 mon
->osdmon()->do_set_pool_opt(metadata
,
263 pool_opts_t::RECOVERY_PRIORITY
,
264 static_cast<int64_t>(5));
265 mon
->osdmon()->do_set_pool_opt(metadata
,
266 pool_opts_t::PG_NUM_MIN
,
267 static_cast<int64_t>(16));
268 mon
->osdmon()->do_set_pool_opt(metadata
,
269 pool_opts_t::PG_AUTOSCALE_BIAS
,
270 static_cast<double>(4.0));
271 mon
->osdmon()->propose_pending();
273 // All checks passed, go ahead and create.
274 auto&& fs
= fsmap
.create_filesystem(fs_name
, metadata
, data
,
275 mon
->get_quorum_con_features());
277 ss
<< "new fs with metadata pool " << metadata
<< " and data pool " << data
;
279 // assign a standby to rank 0 to avoid health warnings
281 mds_gid_t gid
= fsmap
.find_replacement_for({fs
->fscid
, 0}, _name
);
283 if (gid
!= MDS_GID_NONE
) {
284 const auto &info
= fsmap
.get_info_gid(gid
);
285 mon
->clog
->info() << info
.human_name() << " assigned to filesystem "
286 << fs_name
<< " as rank 0";
287 fsmap
.promote(gid
, *fs
, 0);
297 class SetHandler
: public FileSystemCommandHandler
301 : FileSystemCommandHandler("fs set")
308 const cmdmap_t
& cmdmap
,
309 std::stringstream
&ss
) override
312 if (!cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
) || fs_name
.empty()) {
313 ss
<< "Missing filesystem name";
317 auto fs
= fsmap
.get_filesystem(fs_name
);
319 ss
<< "Not found: '" << fs_name
<< "'";
324 if (!cmd_getval(g_ceph_context
, cmdmap
, "var", var
) || var
.empty()) {
325 ss
<< "Invalid variable";
331 if (!cmd_getval(g_ceph_context
, cmdmap
, "val", val
)) {
334 // we got a string. see if it contains an int.
335 n
= strict_strtoll(val
.c_str(), 10, &interr
);
336 if (var
== "max_mds") {
337 // NOTE: see also "mds set_max_mds", which can modify the same field.
338 if (interr
.length()) {
344 ss
<< "You must specify at least one MDS";
347 if (n
> 1 && n
> fs
->mds_map
.get_max_mds()) {
348 if (fs
->mds_map
.was_snaps_ever_allowed() &&
349 !fs
->mds_map
.allows_multimds_snaps()) {
350 ss
<< "multi-active MDS is not allowed while there are snapshots possibly created by pre-mimic MDS";
355 ss
<< "may not have more than " << MAX_MDS
<< " MDS ranks";
359 fsmap
.modify_filesystem(
361 [n
](std::shared_ptr
<Filesystem
> fs
)
363 fs
->mds_map
.clear_flag(CEPH_MDSMAP_NOT_JOINABLE
);
364 fs
->mds_map
.set_max_mds(n
);
366 } else if (var
== "inline_data") {
367 bool enable_inline
= false;
368 int r
= parse_bool(val
, &enable_inline
, ss
);
374 bool confirm
= false;
375 cmd_getval(g_ceph_context
, cmdmap
, "yes_i_really_mean_it", confirm
);
377 ss
<< EXPERIMENTAL_WARNING
;
380 ss
<< "inline data enabled";
382 fsmap
.modify_filesystem(
384 [](std::shared_ptr
<Filesystem
> fs
)
386 fs
->mds_map
.set_inline_data_enabled(true);
390 CompatSet c
= fsmap
.get_compat();
391 c
.incompat
.insert(MDS_FEATURE_INCOMPAT_INLINE
);
392 fsmap
.update_compat(c
);
394 ss
<< "inline data disabled";
395 fsmap
.modify_filesystem(
397 [](std::shared_ptr
<Filesystem
> fs
)
399 fs
->mds_map
.set_inline_data_enabled(false);
402 } else if (var
== "balancer") {
404 ss
<< "unsetting the metadata load balancer";
406 ss
<< "setting the metadata load balancer to " << val
;
408 fsmap
.modify_filesystem(
410 [val
](std::shared_ptr
<Filesystem
> fs
)
412 fs
->mds_map
.set_balancer(val
);
415 } else if (var
== "max_file_size") {
416 if (interr
.length()) {
417 ss
<< var
<< " requires an integer value";
420 if (n
< CEPH_MIN_STRIPE_UNIT
) {
421 ss
<< var
<< " must at least " << CEPH_MIN_STRIPE_UNIT
;
424 fsmap
.modify_filesystem(
426 [n
](std::shared_ptr
<Filesystem
> fs
)
428 fs
->mds_map
.set_max_filesize(n
);
430 } else if (var
== "allow_new_snaps") {
431 bool enable_snaps
= false;
432 int r
= parse_bool(val
, &enable_snaps
, ss
);
438 fsmap
.modify_filesystem(
440 [](std::shared_ptr
<Filesystem
> fs
)
442 fs
->mds_map
.clear_snaps_allowed();
444 ss
<< "disabled new snapshots";
446 fsmap
.modify_filesystem(
448 [](std::shared_ptr
<Filesystem
> fs
)
450 fs
->mds_map
.set_snaps_allowed();
452 ss
<< "enabled new snapshots";
454 } else if (var
== "allow_multimds") {
455 ss
<< "Multiple MDS is always enabled. Use the max_mds"
456 << " parameter to control the number of active MDSs"
457 << " allowed. This command is DEPRECATED and will be"
458 << " REMOVED from future releases.";
459 } else if (var
== "allow_multimds_snaps") {
461 int r
= parse_bool(val
, &enable
, ss
);
467 if (!cmd_getval(g_ceph_context
, cmdmap
, "confirm", confirm
) ||
468 confirm
!= "--yes-i-am-really-a-mds") {
469 ss
<< "Warning! This command is for MDS only. Do not run it manually";
474 ss
<< "enabled multimds with snapshot";
475 fsmap
.modify_filesystem(
477 [](std::shared_ptr
<Filesystem
> fs
)
479 fs
->mds_map
.set_multimds_snaps_allowed();
482 ss
<< "disabled multimds with snapshot";
483 fsmap
.modify_filesystem(
485 [](std::shared_ptr
<Filesystem
> fs
)
487 fs
->mds_map
.clear_multimds_snaps_allowed();
490 } else if (var
== "allow_dirfrags") {
491 ss
<< "Directory fragmentation is now permanently enabled."
492 << " This command is DEPRECATED and will be REMOVED from future releases.";
493 } else if (var
== "down") {
494 bool is_down
= false;
495 int r
= parse_bool(val
, &is_down
, ss
);
500 ss
<< fs
->mds_map
.get_fs_name();
502 fsmap
.modify_filesystem(
504 [is_down
](std::shared_ptr
<Filesystem
> fs
)
507 if (fs
->mds_map
.get_max_mds() > 0) {
508 fs
->mds_map
.set_old_max_mds();
509 fs
->mds_map
.set_max_mds(0);
510 } /* else already down! */
512 mds_rank_t oldmax
= fs
->mds_map
.get_old_max_mds();
513 fs
->mds_map
.set_max_mds(oldmax
? oldmax
: 1);
518 ss
<< " marked down. ";
520 ss
<< " marked up, max_mds = " << fs
->mds_map
.get_max_mds();
522 } else if (var
== "cluster_down" || var
== "joinable") {
523 bool joinable
= true;
524 int r
= parse_bool(val
, &joinable
, ss
);
528 if (var
== "cluster_down") {
529 joinable
= !joinable
;
532 ss
<< fs
->mds_map
.get_fs_name();
534 fsmap
.modify_filesystem(
536 [joinable
](std::shared_ptr
<Filesystem
> fs
)
539 fs
->mds_map
.clear_flag(CEPH_MDSMAP_NOT_JOINABLE
);
541 fs
->mds_map
.set_flag(CEPH_MDSMAP_NOT_JOINABLE
);
546 ss
<< " marked joinable; MDS may join as newly active.";
548 ss
<< " marked not joinable; MDS cannot join as newly active.";
551 if (var
== "cluster_down") {
552 ss
<< " WARNING: cluster_down flag is deprecated and will be"
553 << " removed in a future version. Please use \"joinable\".";
555 } else if (var
== "standby_count_wanted") {
556 if (interr
.length()) {
557 ss
<< var
<< " requires an integer value";
561 ss
<< var
<< " must be non-negative";
564 fsmap
.modify_filesystem(
566 [n
](std::shared_ptr
<Filesystem
> fs
)
568 fs
->mds_map
.set_standby_count_wanted(n
);
570 } else if (var
== "session_timeout") {
571 if (interr
.length()) {
572 ss
<< var
<< " requires an integer value";
576 ss
<< var
<< " must be at least 30s";
579 fsmap
.modify_filesystem(
581 [n
](std::shared_ptr
<Filesystem
> fs
)
583 fs
->mds_map
.set_session_timeout((uint32_t)n
);
585 } else if (var
== "session_autoclose") {
586 if (interr
.length()) {
587 ss
<< var
<< " requires an integer value";
591 ss
<< var
<< " must be at least 30s";
594 fsmap
.modify_filesystem(
596 [n
](std::shared_ptr
<Filesystem
> fs
)
598 fs
->mds_map
.set_session_autoclose((uint32_t)n
);
600 } else if (var
== "allow_standby_replay") {
602 int r
= parse_bool(val
, &allow
, ss
);
607 auto f
= [allow
](auto& fs
) {
609 fs
->mds_map
.set_standby_replay_allowed();
611 fs
->mds_map
.clear_standby_replay_allowed();
614 fsmap
.modify_filesystem(fs
->fscid
, std::move(f
));
615 } else if (var
== "min_compat_client") {
616 int vno
= ceph_release_from_name(val
.c_str());
618 ss
<< "version " << val
<< " is not recognized";
621 fsmap
.modify_filesystem(
623 [vno
](std::shared_ptr
<Filesystem
> fs
)
625 fs
->mds_map
.set_min_compat_client((uint8_t)vno
);
628 ss
<< "unknown variable " << var
;
636 class AddDataPoolHandler
: public FileSystemCommandHandler
639 explicit AddDataPoolHandler(Paxos
*paxos
)
640 : FileSystemCommandHandler("fs add_data_pool"), m_paxos(paxos
)
643 bool batched_propose() override
{
651 const cmdmap_t
& cmdmap
,
652 std::stringstream
&ss
) override
654 ceph_assert(m_paxos
->is_plugged());
657 cmd_getval(g_ceph_context
, cmdmap
, "pool", poolname
);
660 if (!cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
)
661 || fs_name
.empty()) {
662 ss
<< "Missing filesystem name";
666 auto fs
= fsmap
.get_filesystem(fs_name
);
668 ss
<< "Not found: '" << fs_name
<< "'";
672 int64_t poolid
= mon
->osdmon()->osdmap
.lookup_pg_pool_name(poolname
);
675 poolid
= strict_strtol(poolname
.c_str(), 10, &err
);
677 ss
<< "pool '" << poolname
<< "' does not exist";
682 int r
= _check_pool(mon
->osdmon()->osdmap
, poolid
, POOL_DATA_EXTRA
, false, &ss
);
687 // no-op when the data_pool already on fs
688 if (fs
->mds_map
.is_data_pool(poolid
)) {
689 ss
<< "data pool " << poolid
<< " is already on fs " << fs_name
;
693 if (!mon
->osdmon()->is_writeable()) {
694 // not allowed to write yet, so retry when we can
695 mon
->osdmon()->wait_for_writeable(op
, new PaxosService::C_RetryMessage(mon
->mdsmon(), op
));
698 mon
->osdmon()->do_application_enable(poolid
,
699 pg_pool_t::APPLICATION_NAME_CEPHFS
,
701 mon
->osdmon()->propose_pending();
703 fsmap
.modify_filesystem(
705 [poolid
](std::shared_ptr
<Filesystem
> fs
)
707 fs
->mds_map
.add_data_pool(poolid
);
710 ss
<< "added data pool " << poolid
<< " to fsmap";
719 class SetDefaultHandler
: public FileSystemCommandHandler
723 : FileSystemCommandHandler("fs set-default")
730 const cmdmap_t
& cmdmap
,
731 std::stringstream
&ss
) override
734 cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
);
735 auto fs
= fsmap
.get_filesystem(fs_name
);
737 ss
<< "filesystem '" << fs_name
<< "' does not exist";
741 fsmap
.set_legacy_client_fscid(fs
->fscid
);
746 class RemoveFilesystemHandler
: public FileSystemCommandHandler
749 RemoveFilesystemHandler()
750 : FileSystemCommandHandler("fs rm")
757 const cmdmap_t
& cmdmap
,
758 std::stringstream
&ss
) override
760 /* We may need to blacklist ranks. */
761 if (!mon
->osdmon()->is_writeable()) {
762 // not allowed to write yet, so retry when we can
763 mon
->osdmon()->wait_for_writeable(op
, new PaxosService::C_RetryMessage(mon
->mdsmon(), op
));
767 // Check caller has correctly named the FS to delete
768 // (redundant while there is only one FS, but command
769 // syntax should apply to multi-FS future)
771 cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
);
772 auto fs
= fsmap
.get_filesystem(fs_name
);
774 // Consider absence success to make deletes idempotent
775 ss
<< "filesystem '" << fs_name
<< "' does not exist";
779 // Check that no MDS daemons are active
780 if (fs
->mds_map
.get_num_up_mds() > 0) {
781 ss
<< "all MDS daemons must be inactive/failed before removing filesystem. See `ceph fs fail`.";
785 // Check for confirmation flag
787 cmd_getval(g_ceph_context
, cmdmap
, "yes_i_really_mean_it", sure
);
789 ss
<< "this is a DESTRUCTIVE operation and will make data in your filesystem permanently" \
790 " inaccessible. Add --yes-i-really-mean-it if you are sure you wish to continue.";
794 if (fsmap
.get_legacy_client_fscid() == fs
->fscid
) {
795 fsmap
.set_legacy_client_fscid(FS_CLUSTER_ID_NONE
);
798 std::vector
<mds_gid_t
> to_fail
;
799 // There may be standby_replay daemons left here
800 for (const auto &i
: fs
->mds_map
.get_mds_info()) {
801 ceph_assert(i
.second
.state
== MDSMap::STATE_STANDBY_REPLAY
);
802 to_fail
.push_back(i
.first
);
805 for (const auto &gid
: to_fail
) {
806 // Standby replays don't write, so it isn't important to
807 // wait for an osdmap propose here: ignore return value.
808 mon
->mdsmon()->fail_mds_gid(fsmap
, gid
);
810 if (!to_fail
.empty()) {
811 mon
->osdmon()->propose_pending(); /* maybe new blacklists */
814 fsmap
.erase_filesystem(fs
->fscid
);
820 class ResetFilesystemHandler
: public FileSystemCommandHandler
823 ResetFilesystemHandler()
824 : FileSystemCommandHandler("fs reset")
831 const cmdmap_t
& cmdmap
,
832 std::stringstream
&ss
) override
835 cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
);
836 auto fs
= fsmap
.get_filesystem(fs_name
);
838 ss
<< "filesystem '" << fs_name
<< "' does not exist";
839 // Unlike fs rm, we consider this case an error
843 // Check that no MDS daemons are active
844 if (fs
->mds_map
.get_num_up_mds() > 0) {
845 ss
<< "all MDS daemons must be inactive before resetting filesystem: set the cluster_down flag"
846 " and use `ceph mds fail` to make this so";
850 // Check for confirmation flag
852 cmd_getval(g_ceph_context
, cmdmap
, "yes_i_really_mean_it", sure
);
854 ss
<< "this is a potentially destructive operation, only for use by experts in disaster recovery. "
855 "Add --yes-i-really-mean-it if you are sure you wish to continue.";
859 fsmap
.reset_filesystem(fs
->fscid
);
865 class RemoveDataPoolHandler
: public FileSystemCommandHandler
868 RemoveDataPoolHandler()
869 : FileSystemCommandHandler("fs rm_data_pool")
876 const cmdmap_t
& cmdmap
,
877 std::stringstream
&ss
) override
880 cmd_getval(g_ceph_context
, cmdmap
, "pool", poolname
);
883 if (!cmd_getval(g_ceph_context
, cmdmap
, "fs_name", fs_name
)
884 || fs_name
.empty()) {
885 ss
<< "Missing filesystem name";
889 auto fs
= fsmap
.get_filesystem(fs_name
);
891 ss
<< "Not found: '" << fs_name
<< "'";
895 int64_t poolid
= mon
->osdmon()->osdmap
.lookup_pg_pool_name(poolname
);
898 poolid
= strict_strtol(poolname
.c_str(), 10, &err
);
900 ss
<< "pool '" << poolname
<< "' does not exist";
902 } else if (poolid
< 0) {
903 ss
<< "invalid pool id '" << poolid
<< "'";
908 ceph_assert(poolid
>= 0); // Checked by parsing code above
910 if (fs
->mds_map
.get_first_data_pool() == poolid
) {
911 ss
<< "cannot remove default data pool";
917 fsmap
.modify_filesystem(fs
->fscid
,
918 [&r
, poolid
](std::shared_ptr
<Filesystem
> fs
)
920 r
= fs
->mds_map
.remove_data_pool(poolid
);
923 // It was already removed, succeed in silence
926 // We removed it, succeed
927 ss
<< "removed data pool " << poolid
<< " from fsmap";
930 // Unexpected error, bubble up
937 * For commands with an alternative prefix
940 class AliasHandler
: public T
942 std::string alias_prefix
;
945 explicit AliasHandler(const std::string
&new_prefix
)
948 alias_prefix
= new_prefix
;
951 std::string
const &get_prefix() override
{return alias_prefix
;}
957 const cmdmap_t
& cmdmap
,
958 std::stringstream
&ss
) override
960 return T::handle(mon
, fsmap
, op
, cmdmap
, ss
);
965 std::list
<std::shared_ptr
<FileSystemCommandHandler
> >
966 FileSystemCommandHandler::load(Paxos
*paxos
)
968 std::list
<std::shared_ptr
<FileSystemCommandHandler
> > handlers
;
970 handlers
.push_back(std::make_shared
<SetHandler
>());
971 handlers
.push_back(std::make_shared
<FailHandler
>());
972 handlers
.push_back(std::make_shared
<FlagSetHandler
>());
973 handlers
.push_back(std::make_shared
<AddDataPoolHandler
>(paxos
));
974 handlers
.push_back(std::make_shared
<RemoveDataPoolHandler
>());
975 handlers
.push_back(std::make_shared
<FsNewHandler
>(paxos
));
976 handlers
.push_back(std::make_shared
<RemoveFilesystemHandler
>());
977 handlers
.push_back(std::make_shared
<ResetFilesystemHandler
>());
979 handlers
.push_back(std::make_shared
<SetDefaultHandler
>());
980 handlers
.push_back(std::make_shared
<AliasHandler
<SetDefaultHandler
> >(
986 int FileSystemCommandHandler::_check_pool(
988 const int64_t pool_id
,
991 std::stringstream
*ss
) const
993 ceph_assert(ss
!= NULL
);
995 const pg_pool_t
*pool
= osd_map
.get_pg_pool(pool_id
);
997 *ss
<< "pool id '" << pool_id
<< "' does not exist";
1001 const string
& pool_name
= osd_map
.get_pool_name(pool_id
);
1003 if (pool
->is_erasure()) {
1004 if (type
== POOL_METADATA
) {
1005 *ss
<< "pool '" << pool_name
<< "' (id '" << pool_id
<< "')"
1006 << " is an erasure-coded pool. Use of erasure-coded pools"
1007 << " for CephFS metadata is not permitted";
1009 } else if (type
== POOL_DATA_DEFAULT
&& !force
) {
1010 *ss
<< "pool '" << pool_name
<< "' (id '" << pool_id
<< "')"
1011 " is an erasure-coded pool."
1012 " Use of an EC pool for the default data pool is discouraged;"
1013 " see the online CephFS documentation for more information."
1014 " Use --force to override.";
1016 } else if (!pool
->allows_ecoverwrites()) {
1017 // non-overwriteable EC pools are only acceptable with a cache tier overlay
1018 if (!pool
->has_tiers() || !pool
->has_read_tier() || !pool
->has_write_tier()) {
1019 *ss
<< "pool '" << pool_name
<< "' (id '" << pool_id
<< "')"
1020 << " is an erasure-coded pool, with no overwrite support";
1024 // That cache tier overlay must be writeback, not readonly (it's the
1025 // write operations like modify+truncate we care about support for)
1026 const pg_pool_t
*write_tier
= osd_map
.get_pg_pool(
1028 ceph_assert(write_tier
!= NULL
); // OSDMonitor shouldn't allow DNE tier
1029 if (write_tier
->cache_mode
== pg_pool_t::CACHEMODE_FORWARD
1030 || write_tier
->cache_mode
== pg_pool_t::CACHEMODE_READONLY
) {
1031 *ss
<< "EC pool '" << pool_name
<< "' has a write tier ("
1032 << osd_map
.get_pool_name(pool
->write_tier
)
1033 << ") that is configured "
1034 "to forward writes. Use a cache mode such as 'writeback' for "
1041 if (pool
->is_tier()) {
1042 *ss
<< " pool '" << pool_name
<< "' (id '" << pool_id
1043 << "') is already in use as a cache tier.";
1047 if (!force
&& !pool
->application_metadata
.empty() &&
1048 pool
->application_metadata
.count(
1049 pg_pool_t::APPLICATION_NAME_CEPHFS
) == 0) {
1050 *ss
<< " pool '" << pool_name
<< "' (id '" << pool_id
1051 << "') has a non-CephFS application enabled.";
1055 // Nothing special about this pool, so it is permissible