Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / operation / SnapshotRemoveRequest.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 "librbd/operation/SnapshotRemoveRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/ExclusiveLock.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ObjectMap.h"
10
11 #define dout_subsys ceph_subsys_rbd
12 #undef dout_prefix
13 #define dout_prefix *_dout << "librbd::SnapshotRemoveRequest: "
14
15 namespace librbd {
16 namespace operation {
17
18 namespace {
19
20 template <typename I>
21 std::ostream& operator<<(std::ostream& os,
22                          const typename SnapshotRemoveRequest<I>::State& state) {
23   switch(state) {
24   case SnapshotRemoveRequest<I>::STATE_REMOVE_OBJECT_MAP:
25     os << "REMOVE_OBJECT_MAP";
26     break;
27   case SnapshotRemoveRequest<I>::STATE_REMOVE_CHILD:
28     os << "REMOVE_CHILD";
29     break;
30   case SnapshotRemoveRequest<I>::STATE_REMOVE_SNAP:
31     os << "REMOVE_SNAP";
32     break;
33   case SnapshotRemoveRequest<I>::STATE_RELEASE_SNAP_ID:
34     os << "RELEASE_SNAP_ID";
35     break;
36   case SnapshotRemoveRequest<I>::STATE_ERROR:
37     os << "STATE_ERROR";
38     break;
39   default:
40     os << "UNKNOWN (" << static_cast<uint32_t>(state) << ")";
41     break;
42   }
43   return os;
44 }
45
46 } // anonymous namespace
47
48 template <typename I>
49 SnapshotRemoveRequest<I>::SnapshotRemoveRequest(I &image_ctx,
50                                                 Context *on_finish,
51                                                 const cls::rbd::SnapshotNamespace &snap_namespace,
52                                                 const std::string &snap_name,
53                                                 uint64_t snap_id)
54   : Request<I>(image_ctx, on_finish), m_snap_namespace(snap_namespace),
55     m_snap_name(snap_name), m_snap_id(snap_id) {
56 }
57
58 template <typename I>
59 void SnapshotRemoveRequest<I>::send_op() {
60   send_remove_object_map();
61 }
62
63 template <typename I>
64 bool SnapshotRemoveRequest<I>::should_complete(int r) {
65   I &image_ctx = this->m_image_ctx;
66   CephContext *cct = image_ctx.cct;
67   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
68                 << "r=" << r << dendl;
69   r = filter_state_return_code(r);
70   if (r < 0) {
71     return true;
72   }
73
74   RWLock::RLocker owner_lock(image_ctx.owner_lock);
75   bool finished = false;
76   switch (m_state) {
77   case STATE_REMOVE_OBJECT_MAP:
78     send_remove_child();
79     break;
80   case STATE_REMOVE_CHILD:
81     send_remove_snap();
82     break;
83   case STATE_REMOVE_SNAP:
84     remove_snap_context();
85     send_release_snap_id();
86     break;
87   case STATE_RELEASE_SNAP_ID:
88     finished = true;
89     break;
90   default:
91     assert(false);
92     break;
93   }
94
95   return finished;
96 }
97
98 template <typename I>
99 void SnapshotRemoveRequest<I>::send_remove_object_map() {
100   I &image_ctx = this->m_image_ctx;
101   assert(image_ctx.owner_lock.is_locked());
102
103   {
104     CephContext *cct = image_ctx.cct;
105     RWLock::WLocker snap_locker(image_ctx.snap_lock);
106     RWLock::RLocker object_map_locker(image_ctx.object_map_lock);
107     if (image_ctx.snap_info.find(m_snap_id) == image_ctx.snap_info.end()) {
108       lderr(cct) << this << " " << __func__ << ": snapshot doesn't exist"
109                  << dendl;
110       this->async_complete(-ENOENT);
111       return;
112     }
113
114     if (image_ctx.object_map != nullptr) {
115       ldout(cct, 5) << this << " " << __func__ << dendl;
116       m_state = STATE_REMOVE_OBJECT_MAP;
117
118       image_ctx.object_map->snapshot_remove(
119         m_snap_id, this->create_callback_context());
120       return;
121     }
122   }
123   send_remove_child();
124 }
125
126 template <typename I>
127 void SnapshotRemoveRequest<I>::send_remove_child() {
128   I &image_ctx = this->m_image_ctx;
129   assert(image_ctx.owner_lock.is_locked());
130
131   CephContext *cct = image_ctx.cct;
132   {
133     RWLock::RLocker snap_locker(image_ctx.snap_lock);
134     RWLock::RLocker parent_locker(image_ctx.parent_lock);
135
136     ParentSpec our_pspec;
137     int r = image_ctx.get_parent_spec(m_snap_id, &our_pspec);
138     if (r < 0) {
139       if (r == -ENOENT) {
140         ldout(cct, 1) << "No such snapshot" << dendl;
141       } else {
142         lderr(cct) << "failed to retrieve parent spec" << dendl;
143       }
144       m_state = STATE_ERROR;
145
146       this->async_complete(r);
147       return;
148     }
149
150     if (image_ctx.parent_md.spec != our_pspec &&
151         (scan_for_parents(our_pspec) == -ENOENT)) {
152       // no other references to the parent image
153       ldout(cct, 5) << this << " " << __func__ << dendl;
154       m_state = STATE_REMOVE_CHILD;
155
156       librados::ObjectWriteOperation op;
157       cls_client::remove_child(&op, our_pspec, image_ctx.id);
158
159       librados::AioCompletion *rados_completion = this->create_callback_completion();
160       r = image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
161       assert(r == 0);
162       rados_completion->release();
163       return;
164     }
165   }
166
167   // HEAD image or other snapshots still associated with parent
168   send_remove_snap();
169 }
170
171 template <typename I>
172 void SnapshotRemoveRequest<I>::send_remove_snap() {
173   I &image_ctx = this->m_image_ctx;
174   assert(image_ctx.owner_lock.is_locked());
175
176   CephContext *cct = image_ctx.cct;
177   ldout(cct, 5) << this << " " << __func__ << dendl;
178   m_state = STATE_REMOVE_SNAP;
179
180   librados::ObjectWriteOperation op;
181   if (image_ctx.old_format) {
182     cls_client::old_snapshot_remove(&op, m_snap_name);
183   } else {
184     cls_client::snapshot_remove(&op, m_snap_id);
185   }
186
187   librados::AioCompletion *rados_completion = this->create_callback_completion();
188   int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
189                                        rados_completion, &op);
190   assert(r == 0);
191   rados_completion->release();
192 }
193
194 template <typename I>
195 void SnapshotRemoveRequest<I>::send_release_snap_id() {
196   I &image_ctx = this->m_image_ctx;
197   assert(image_ctx.owner_lock.is_locked());
198
199   CephContext *cct = image_ctx.cct;
200   ldout(cct, 5) << this << " " << __func__ << ": "
201                 << "snap_name=" << m_snap_name << ", "
202                 << "snap_id=" << m_snap_id << dendl;
203   m_state = STATE_RELEASE_SNAP_ID;
204
205   librados::AioCompletion *rados_completion =
206     this->create_callback_completion();
207   image_ctx.data_ctx.aio_selfmanaged_snap_remove(m_snap_id, rados_completion);
208   rados_completion->release();
209 }
210
211 template <typename I>
212 void SnapshotRemoveRequest<I>::remove_snap_context() {
213   I &image_ctx = this->m_image_ctx;
214   CephContext *cct = image_ctx.cct;
215   ldout(cct, 5) << this << " " << __func__ << dendl;
216
217   RWLock::WLocker snap_locker(image_ctx.snap_lock);
218   image_ctx.rm_snap(m_snap_namespace, m_snap_name, m_snap_id);
219 }
220
221 template <typename I>
222 int SnapshotRemoveRequest<I>::scan_for_parents(ParentSpec &pspec) {
223   I &image_ctx = this->m_image_ctx;
224   assert(image_ctx.snap_lock.is_locked());
225   assert(image_ctx.parent_lock.is_locked());
226
227   if (pspec.pool_id != -1) {
228     map<uint64_t, SnapInfo>::iterator it;
229     for (it = image_ctx.snap_info.begin();
230          it != image_ctx.snap_info.end(); ++it) {
231       // skip our snap id (if checking base image, CEPH_NOSNAP won't match)
232       if (it->first == m_snap_id) {
233         continue;
234       }
235       if (it->second.parent.spec == pspec) {
236         break;
237       }
238     }
239     if (it == image_ctx.snap_info.end()) {
240       return -ENOENT;
241     }
242   }
243   return 0;
244 }
245
246 } // namespace operation
247 } // namespace librbd
248
249 template class librbd::operation::SnapshotRemoveRequest<librbd::ImageCtx>;