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