// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/errno.h" #include "cls/rbd/cls_rbd_client.h" #include "librbd/api/Mirror.h" #include "librbd/api/Namespace.h" #include "librbd/ImageCtx.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::api::Namespace: " << __func__ << ": " namespace librbd { namespace api { namespace { const std::list POOL_OBJECTS { RBD_CHILDREN, RBD_GROUP_DIRECTORY, RBD_INFO, RBD_MIRRORING, RBD_TASK, RBD_TRASH, RBD_DIRECTORY }; } // anonymous namespace template int Namespace::create(librados::IoCtx& io_ctx, const std::string& name) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 5) << "name=" << name << dendl; if (name.empty()) { return -EINVAL; } librados::Rados rados(io_ctx); int8_t require_osd_release; int r = rados.get_min_compatible_osd(&require_osd_release); if (r < 0) { lderr(cct) << "failed to retrieve min OSD release: " << cpp_strerror(r) << dendl; return r; } if (require_osd_release < CEPH_RELEASE_NAUTILUS) { ldout(cct, 1) << "namespace support requires nautilus or later OSD" << dendl; return -ENOSYS; } librados::IoCtx default_ns_ctx; default_ns_ctx.dup(io_ctx); default_ns_ctx.set_namespace(""); r = cls_client::namespace_add(&default_ns_ctx, name); if (r < 0) { lderr(cct) << "failed to add namespace: " << cpp_strerror(r) << dendl; return r; } librados::IoCtx ns_ctx; ns_ctx.dup(io_ctx); ns_ctx.set_namespace(name); r = cls_client::dir_state_set(&ns_ctx, RBD_DIRECTORY, cls::rbd::DIRECTORY_STATE_READY); if (r < 0) { lderr(cct) << "failed to initialize image directory: " << cpp_strerror(r) << dendl; goto rollback; } return 0; rollback: int ret_val = cls_client::namespace_remove(&default_ns_ctx, name); if (ret_val < 0) { lderr(cct) << "failed to remove namespace: " << cpp_strerror(ret_val) << dendl; } return r; } template int Namespace::remove(librados::IoCtx& io_ctx, const std::string& name) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 5) << "name=" << name << dendl; if (name.empty()) { return -EINVAL; } librados::IoCtx default_ns_ctx; default_ns_ctx.dup(io_ctx); default_ns_ctx.set_namespace(""); librados::IoCtx ns_ctx; ns_ctx.dup(io_ctx); ns_ctx.set_namespace(name); std::map trash_entries; librados::ObjectWriteOperation dir_op; librbd::cls_client::dir_state_set( &dir_op, cls::rbd::DIRECTORY_STATE_ADD_DISABLED); dir_op.remove(); int r = ns_ctx.operate(RBD_DIRECTORY, &dir_op); if (r == -EBUSY) { ldout(cct, 5) << "image directory not empty" << dendl; goto rollback; } else if (r < 0 && r != -ENOENT) { lderr(cct) << "failed to disable the namespace: " << cpp_strerror(r) << dendl; return r; } r = cls_client::trash_list(&ns_ctx, "", 1, &trash_entries); if (r < 0 && r != -ENOENT) { lderr(cct) << "failed to list trash directory: " << cpp_strerror(r) << dendl; return r; } else if (!trash_entries.empty()) { ldout(cct, 5) << "image trash not empty" << dendl; goto rollback; } r = Mirror::mode_set(ns_ctx, RBD_MIRROR_MODE_DISABLED); if (r < 0) { lderr(cct) << "failed to disable mirroring: " << cpp_strerror(r) << dendl; return r; } for (auto& oid : POOL_OBJECTS) { r = ns_ctx.remove(oid); if (r < 0 && r != -ENOENT) { lderr(cct) << "failed to remove object '" << oid << "': " << cpp_strerror(r) << dendl; return r; } } r = cls_client::namespace_remove(&default_ns_ctx, name); if (r < 0) { lderr(cct) << "failed to remove namespace: " << cpp_strerror(r) << dendl; return r; } return 0; rollback: r = librbd::cls_client::dir_state_set( &ns_ctx, RBD_DIRECTORY, cls::rbd::DIRECTORY_STATE_READY); if (r < 0) { lderr(cct) << "failed to restore directory state: " << cpp_strerror(r) << dendl; } return -EBUSY; } template int Namespace::list(IoCtx& io_ctx, vector *names) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 5) << dendl; librados::IoCtx default_ns_ctx; default_ns_ctx.dup(io_ctx); default_ns_ctx.set_namespace(""); int r; int max_read = 1024; std::string last_read = ""; do { std::list name_list; r = cls_client::namespace_list(&default_ns_ctx, last_read, max_read, &name_list); if (r == -ENOENT) { return 0; } else if (r < 0) { lderr(cct) << "error listing namespaces: " << cpp_strerror(r) << dendl; return r; } names->insert(names->end(), name_list.begin(), name_list.end()); if (!name_list.empty()) { last_read = name_list.back(); } r = name_list.size(); } while (r == max_read); return 0; } template int Namespace::exists(librados::IoCtx& io_ctx, const std::string& name, bool *exists) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 5) << "name=" << name << dendl; *exists = false; if (name.empty()) { return -EINVAL; } librados::IoCtx ns_ctx; ns_ctx.dup(io_ctx); ns_ctx.set_namespace(name); int r = librbd::cls_client::dir_state_assert(&ns_ctx, RBD_DIRECTORY, cls::rbd::DIRECTORY_STATE_READY); if (r == 0) { *exists = true; } else if (r != -ENOENT) { lderr(cct) << "error asserting namespace: " << cpp_strerror(r) << dendl; return r; } return 0; } } // namespace api } // namespace librbd template class librbd::api::Namespace;