]>
Commit | Line | Data |
---|---|---|
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 | ||
13 | namespace librbd { | |
14 | namespace api { | |
15 | ||
92f5a8d4 TL |
16 | namespace { |
17 | ||
18 | const 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 |
30 | template <typename I> |
31 | int 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 | ||
80 | rollback: | |
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 | ||
89 | template <typename I> | |
90 | int 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 | ||
151 | rollback: | |
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 | ||
163 | template <typename I> | |
164 | int 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 | ||
197 | template <typename I> | |
198 | int 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 | ||
227 | template class librbd::api::Namespace<librbd::ImageCtx>; |