1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
11 #define dout_subsys ceph_subsys_rbd
13 #define dout_prefix *_dout << "librbd::SnapshotRemoveRequest: "
21 std::ostream& operator<<(std::ostream& os,
22 const typename SnapshotRemoveRequest<I>::State& state) {
24 case SnapshotRemoveRequest<I>::STATE_REMOVE_OBJECT_MAP:
25 os << "REMOVE_OBJECT_MAP";
27 case SnapshotRemoveRequest<I>::STATE_REMOVE_CHILD:
30 case SnapshotRemoveRequest<I>::STATE_REMOVE_SNAP:
33 case SnapshotRemoveRequest<I>::STATE_RELEASE_SNAP_ID:
34 os << "RELEASE_SNAP_ID";
36 case SnapshotRemoveRequest<I>::STATE_ERROR:
40 os << "UNKNOWN (" << static_cast<uint32_t>(state) << ")";
46 } // anonymous namespace
49 SnapshotRemoveRequest<I>::SnapshotRemoveRequest(I &image_ctx,
51 const cls::rbd::SnapshotNamespace &snap_namespace,
52 const std::string &snap_name,
54 : Request<I>(image_ctx, on_finish), m_snap_namespace(snap_namespace),
55 m_snap_name(snap_name), m_snap_id(snap_id) {
59 void SnapshotRemoveRequest<I>::send_op() {
60 send_remove_object_map();
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);
74 RWLock::RLocker owner_lock(image_ctx.owner_lock);
75 bool finished = false;
77 case STATE_REMOVE_OBJECT_MAP:
80 case STATE_REMOVE_CHILD:
83 case STATE_REMOVE_SNAP:
84 remove_snap_context();
85 send_release_snap_id();
87 case STATE_RELEASE_SNAP_ID:
99 void SnapshotRemoveRequest<I>::send_remove_object_map() {
100 I &image_ctx = this->m_image_ctx;
101 assert(image_ctx.owner_lock.is_locked());
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"
110 this->async_complete(-ENOENT);
114 if (image_ctx.object_map != nullptr) {
115 ldout(cct, 5) << this << " " << __func__ << dendl;
116 m_state = STATE_REMOVE_OBJECT_MAP;
118 image_ctx.object_map->snapshot_remove(
119 m_snap_id, this->create_callback_context());
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());
131 CephContext *cct = image_ctx.cct;
133 RWLock::RLocker snap_locker(image_ctx.snap_lock);
134 RWLock::RLocker parent_locker(image_ctx.parent_lock);
136 ParentSpec our_pspec;
137 int r = image_ctx.get_parent_spec(m_snap_id, &our_pspec);
140 ldout(cct, 1) << "No such snapshot" << dendl;
142 lderr(cct) << "failed to retrieve parent spec" << dendl;
144 m_state = STATE_ERROR;
146 this->async_complete(r);
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;
156 librados::ObjectWriteOperation op;
157 cls_client::remove_child(&op, our_pspec, image_ctx.id);
159 librados::AioCompletion *rados_completion = this->create_callback_completion();
160 r = image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
162 rados_completion->release();
167 // HEAD image or other snapshots still associated with parent
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());
176 CephContext *cct = image_ctx.cct;
177 ldout(cct, 5) << this << " " << __func__ << dendl;
178 m_state = STATE_REMOVE_SNAP;
180 librados::ObjectWriteOperation op;
181 if (image_ctx.old_format) {
182 cls_client::old_snapshot_remove(&op, m_snap_name);
184 cls_client::snapshot_remove(&op, m_snap_id);
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);
191 rados_completion->release();
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());
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;
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();
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;
217 RWLock::WLocker snap_locker(image_ctx.snap_lock);
218 image_ctx.rm_snap(m_snap_namespace, m_snap_name, m_snap_id);
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());
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) {
235 if (it->second.parent.spec == pspec) {
239 if (it == image_ctx.snap_info.end()) {
246 } // namespace operation
247 } // namespace librbd
249 template class librbd::operation::SnapshotRemoveRequest<librbd::ImageCtx>;