]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/api/Namespace.cc
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / librbd / api / Namespace.cc
CommitLineData
11fdf7f2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "common/errno.h"
5#include "cls/rbd/cls_rbd_client.h"
6#include "librbd/api/Namespace.h"
7#include "librbd/ImageCtx.h"
8
9#define dout_subsys ceph_subsys_rbd
10#undef dout_prefix
11#define dout_prefix *_dout << "librbd::api::Namespace: " << __func__ << ": "
12
13namespace librbd {
14namespace api {
15
92f5a8d4
TL
16namespace {
17
18const std::list<std::string> POOL_OBJECTS {
19 RBD_CHILDREN,
20 RBD_GROUP_DIRECTORY,
21 RBD_INFO,
22 RBD_MIRRORING,
23 RBD_TASK,
24 RBD_TRASH,
25 RBD_DIRECTORY
26};
27
28} // anonymous namespace
29
11fdf7f2
TL
30template <typename I>
31int Namespace<I>::create(librados::IoCtx& io_ctx, const std::string& name)
32{
33 CephContext *cct = (CephContext *)io_ctx.cct();
34 ldout(cct, 5) << "name=" << name << dendl;
35
36 if (name.empty()) {
37 return -EINVAL;
38 }
39
40 librados::Rados rados(io_ctx);
41 int8_t require_osd_release;
42 int r = rados.get_min_compatible_osd(&require_osd_release);
43 if (r < 0) {
44 lderr(cct) << "failed to retrieve min OSD release: " << cpp_strerror(r)
45 << dendl;
46 return r;
47 }
48
49 if (require_osd_release < CEPH_RELEASE_NAUTILUS) {
50 ldout(cct, 1) << "namespace support requires nautilus or later OSD"
51 << dendl;
52 return -ENOSYS;
53 }
54
55
56 librados::IoCtx default_ns_ctx;
57 default_ns_ctx.dup(io_ctx);
58 default_ns_ctx.set_namespace("");
59
60 r = cls_client::namespace_add(&default_ns_ctx, name);
61 if (r < 0) {
62 lderr(cct) << "failed to add namespace: " << cpp_strerror(r) << dendl;
63 return r;
64 }
65
66 librados::IoCtx ns_ctx;
67 ns_ctx.dup(io_ctx);
68 ns_ctx.set_namespace(name);
69
70 r = cls_client::dir_state_set(&ns_ctx, RBD_DIRECTORY,
71 cls::rbd::DIRECTORY_STATE_READY);
72 if (r < 0) {
73 lderr(cct) << "failed to initialize image directory: " << cpp_strerror(r)
74 << dendl;
75 goto rollback;
76 }
77
78 return 0;
79
80rollback:
81 int ret_val = cls_client::namespace_remove(&default_ns_ctx, name);
82 if (ret_val < 0) {
83 lderr(cct) << "failed to remove namespace: " << cpp_strerror(ret_val) << dendl;
84 }
85
86 return r;
87}
88
89template <typename I>
90int Namespace<I>::remove(librados::IoCtx& io_ctx, const std::string& name)
91{
92 CephContext *cct = (CephContext *)io_ctx.cct();
93 ldout(cct, 5) << "name=" << name << dendl;
94
95 if (name.empty()) {
96 return -EINVAL;
97 }
98
99 librados::IoCtx default_ns_ctx;
100 default_ns_ctx.dup(io_ctx);
101 default_ns_ctx.set_namespace("");
102
103 librados::IoCtx ns_ctx;
104 ns_ctx.dup(io_ctx);
105 ns_ctx.set_namespace(name);
106
107 std::map<std::string, cls::rbd::TrashImageSpec> trash_entries;
108
109 librados::ObjectWriteOperation dir_op;
110 librbd::cls_client::dir_state_set(
111 &dir_op, cls::rbd::DIRECTORY_STATE_ADD_DISABLED);
112 dir_op.remove();
113
114 int r = ns_ctx.operate(RBD_DIRECTORY, &dir_op);
115 if (r == -EBUSY) {
116 ldout(cct, 5) << "image directory not empty" << dendl;
117 goto rollback;
118 } else if (r < 0 && r != -ENOENT) {
119 lderr(cct) << "failed to disable the namespace: " << cpp_strerror(r)
120 << dendl;
121 return r;
122 }
123
124 r = cls_client::trash_list(&ns_ctx, "", 1, &trash_entries);
125 if (r < 0 && r != -ENOENT) {
126 lderr(cct) << "failed to list trash directory: " << cpp_strerror(r)
127 << dendl;
128 return r;
129 } else if (!trash_entries.empty()) {
130 ldout(cct, 5) << "image trash not empty" << dendl;
131 goto rollback;
132 }
133
92f5a8d4
TL
134 for (auto& oid : POOL_OBJECTS) {
135 r = ns_ctx.remove(oid);
136 if (r < 0 && r != -ENOENT) {
137 lderr(cct) << "failed to remove object '" << oid << "': "
138 << cpp_strerror(r) << dendl;
139 return r;
140 }
141 }
142
11fdf7f2
TL
143 r = cls_client::namespace_remove(&default_ns_ctx, name);
144 if (r < 0) {
145 lderr(cct) << "failed to remove namespace: " << cpp_strerror(r) << dendl;
146 return r;
147 }
148
149 return 0;
150
151rollback:
152
153 r = librbd::cls_client::dir_state_set(
154 &ns_ctx, RBD_DIRECTORY, cls::rbd::DIRECTORY_STATE_READY);
155 if (r < 0) {
156 lderr(cct) << "failed to restore directory state: " << cpp_strerror(r)
157 << dendl;
158 }
159
160 return -EBUSY;
161}
162
163template <typename I>
164int Namespace<I>::list(IoCtx& io_ctx, vector<string> *names)
165{
166 CephContext *cct = (CephContext *)io_ctx.cct();
167 ldout(cct, 5) << dendl;
168
169 librados::IoCtx default_ns_ctx;
170 default_ns_ctx.dup(io_ctx);
171 default_ns_ctx.set_namespace("");
172
173 int r;
174 int max_read = 1024;
175 std::string last_read = "";
176 do {
177 std::list<std::string> name_list;
178 r = cls_client::namespace_list(&default_ns_ctx, last_read, max_read,
179 &name_list);
180 if (r == -ENOENT) {
181 return 0;
182 } else if (r < 0) {
183 lderr(cct) << "error listing namespaces: " << cpp_strerror(r) << dendl;
184 return r;
185 }
186
187 names->insert(names->end(), name_list.begin(), name_list.end());
188 if (!name_list.empty()) {
189 last_read = name_list.back();
190 }
191 r = name_list.size();
192 } while (r == max_read);
193
194 return 0;
195}
196
197template <typename I>
198int Namespace<I>::exists(librados::IoCtx& io_ctx, const std::string& name, bool *exists)
199{
200 CephContext *cct = (CephContext *)io_ctx.cct();
201 ldout(cct, 5) << "name=" << name << dendl;
202
203 *exists = false;
204 if (name.empty()) {
205 return -EINVAL;
206 }
207
208 librados::IoCtx ns_ctx;
209 ns_ctx.dup(io_ctx);
210 ns_ctx.set_namespace(name);
211
212 int r = librbd::cls_client::dir_state_assert(&ns_ctx, RBD_DIRECTORY,
213 cls::rbd::DIRECTORY_STATE_READY);
214 if (r == 0) {
215 *exists = true;
216 } else if (r != -ENOENT) {
217 lderr(cct) << "error asserting namespace: " << cpp_strerror(r) << dendl;
218 return r;
219 }
220
221 return 0;
222}
223
224} // namespace api
225} // namespace librbd
226
227template class librbd::api::Namespace<librbd::ImageCtx>;