1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
5    	#include "common/debug.h"
6    	#include "common/errno.h"
7    	#include "librbd/ExclusiveLock.h"
8    	#include "librbd/ImageCtx.h"
9    	#include "librbd/ImageState.h"
10   	#include "librbd/Operations.h"
11   	#include "librbd/Utils.h"
12   	#include "librbd/journal/Policy.h"
13   	#include "tools/rbd_mirror/image_deleter/Types.h"
14   	
15   	#define dout_context g_ceph_context
16   	#define dout_subsys ceph_subsys_rbd_mirror
17   	#undef dout_prefix
18   	#define dout_prefix *_dout << "rbd::mirror::image_deleter::SnapshotPurgeRequest: " \
19   	                           << this << " " << __func__ << ": "
20   	
21   	namespace rbd {
22   	namespace mirror {
23   	namespace image_deleter {
24   	
25   	using librbd::util::create_context_callback;
26   	
27   	template <typename I>
28   	void SnapshotPurgeRequest<I>::send() {
29   	  open_image();
30   	}
31   	
32   	template <typename I>
33   	void SnapshotPurgeRequest<I>::open_image() {
34   	  dout(10) << dendl;
35   	  m_image_ctx = I::create("", m_image_id, nullptr, m_io_ctx, false);
36   	
37   	  {
38   	    std::unique_lock image_locker{m_image_ctx->image_lock};
39   	    m_image_ctx->set_journal_policy(new JournalPolicy());
40   	  }
41   	
42   	  Context *ctx = create_context_callback<
43   	    SnapshotPurgeRequest<I>, &SnapshotPurgeRequest<I>::handle_open_image>(
44   	      this);
45   	  m_image_ctx->state->open(librbd::OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
46   	}
47   	
48   	template <typename I>
49   	void SnapshotPurgeRequest<I>::handle_open_image(int r) {
50   	  dout(10) << "r=" << r << dendl;
51   	
52   	  if (r < 0) {
53   	    derr << "failed to open image '" << m_image_id << "': " << cpp_strerror(r)
54   	         << dendl;
55   	    m_image_ctx->destroy();
56   	    m_image_ctx = nullptr;
57   	
58   	    finish(r);
59   	    return;
60   	  }
61   	
62   	  acquire_lock();
63   	}
64   	
65   	template <typename I>
66   	void SnapshotPurgeRequest<I>::acquire_lock() {
67   	  dout(10) << dendl;
68   	
69   	  m_image_ctx->owner_lock.lock_shared();
70   	  if (m_image_ctx->exclusive_lock == nullptr) {
71   	    m_image_ctx->owner_lock.unlock_shared();
72   	
73   	    derr << "exclusive lock not enabled" << dendl;
74   	    m_ret_val = -EINVAL;
75   	    close_image();
76   	    return;
77   	  }
78   	
79   	  m_image_ctx->exclusive_lock->acquire_lock(create_context_callback<
80   	    SnapshotPurgeRequest<I>, &SnapshotPurgeRequest<I>::handle_acquire_lock>(
81   	      this));
82   	  m_image_ctx->owner_lock.unlock_shared();
83   	}
84   	
85   	template <typename I>
86   	void SnapshotPurgeRequest<I>::handle_acquire_lock(int r) {
87   	  dout(10) << "r=" << r << dendl;
88   	
89   	  if (r < 0) {
90   	    derr << "failed to acquire exclusive lock: " << cpp_strerror(r) << dendl;
91   	    m_ret_val = r;
92   	    close_image();
93   	    return;
94   	  }
95   	
96   	  {
97   	    std::shared_lock image_locker{m_image_ctx->image_lock};
98   	    m_snaps = m_image_ctx->snaps;
99   	  }
100  	  snap_unprotect();
101  	}
102  	
103  	template <typename I>
104  	void SnapshotPurgeRequest<I>::snap_unprotect() {
(1) Event cond_false: Condition "this->m_snaps.empty()", taking false branch.
105  	  if (m_snaps.empty()) {
106  	    close_image();
107  	    return;
(2) Event if_end: End of if statement.
108  	  }
109  	
110  	  librados::snap_t snap_id = m_snaps.back();
111  	  m_image_ctx->image_lock.lock_shared();
112  	  int r = m_image_ctx->get_snap_namespace(snap_id, &m_snap_namespace);
(3) Event cond_false: Condition "r < 0", taking false branch.
113  	  if (r < 0) {
114  	    m_image_ctx->image_lock.unlock_shared();
115  	
116  	    derr << "failed to get snap namespace: " << cpp_strerror(r) << dendl;
117  	    m_ret_val = r;
118  	    close_image();
119  	    return;
(4) Event if_end: End of if statement.
120  	  }
121  	
122  	  r = m_image_ctx->get_snap_name(snap_id, &m_snap_name);
(5) Event cond_false: Condition "r < 0", taking false branch.
123  	  if (r < 0) {
124  	    m_image_ctx->image_lock.unlock_shared();
125  	
126  	    derr << "failed to get snap name: " << cpp_strerror(r) << dendl;
127  	    m_ret_val = r;
128  	    close_image();
129  	    return;
(6) Event if_end: End of if statement.
130  	  }
131  	
132  	  bool is_protected;
133  	  r = m_image_ctx->is_snap_protected(snap_id, &is_protected);
(7) Event cond_false: Condition "r < 0", taking false branch.
134  	  if (r < 0) {
135  	    m_image_ctx->image_lock.unlock_shared();
136  	
137  	    derr << "failed to get snap protection status: " << cpp_strerror(r)
138  	         << dendl;
139  	    m_ret_val = r;
140  	    close_image();
141  	    return;
(8) Event if_end: End of if statement.
142  	  }
143  	  m_image_ctx->image_lock.unlock_shared();
144  	
(9) Event cond_false: Condition "!is_protected", taking false branch.
145  	  if (!is_protected) {
146  	    snap_remove();
147  	    return;
(10) Event if_end: End of if statement.
148  	  }
149  	
(11) Event cond_true: Condition "should_gather", taking true branch.
150  	  dout(10) << "snap_id=" << snap_id << ", "
151  	           << "snap_namespace=" << m_snap_namespace << ", "
152  	           << "snap_name=" << m_snap_name << dendl;
153  	
154  	  auto finish_op_ctx = start_lock_op(&r);
(12) Event cond_false: Condition "finish_op_ctx == NULL", taking false branch.
155  	  if (finish_op_ctx == nullptr) {
156  	    derr << "lost exclusive lock" << dendl;
157  	    m_ret_val = r;
158  	    close_image();
159  	    return;
(13) Event if_end: End of if statement.
160  	  }
161  	
162  	  auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
163  	      handle_snap_unprotect(r);
164  	      finish_op_ctx->complete(0);
165  	    });
(14) Event lock: "shared_lock" locks "this->m_image_ctx->owner_lock.rwlock". [details]
Also see events: [missing_unlock]
166  	  std::shared_lock owner_locker{m_image_ctx->owner_lock};
167  	  m_image_ctx->operations->execute_snap_unprotect(
168  	    m_snap_namespace, m_snap_name.c_str(), ctx);
(15) Event missing_unlock: Returning without unlocking "this->m_image_ctx->owner_lock.rwlock".
Also see events: [lock]
169  	}
170  	
171  	template <typename I>
172  	void SnapshotPurgeRequest<I>::handle_snap_unprotect(int r) {
173  	  dout(10) << "r=" << r << dendl;
174  	
175  	  if (r == -EBUSY) {
176  	    dout(10) << "snapshot in-use" << dendl;
177  	    m_ret_val = r;
178  	    close_image();
179  	    return;
180  	  } else if (r < 0) {
181  	    derr << "failed to unprotect snapshot: " << cpp_strerror(r) << dendl;
182  	    m_ret_val = r;
183  	    close_image();
184  	    return;
185  	  }
186  	
187  	  {
188  	    // avoid the need to refresh to delete the newly unprotected snapshot
189  	    std::shared_lock image_locker{m_image_ctx->image_lock};
190  	    librados::snap_t snap_id = m_snaps.back();
191  	    auto snap_info_it = m_image_ctx->snap_info.find(snap_id);
192  	    if (snap_info_it != m_image_ctx->snap_info.end()) {
193  	      snap_info_it->second.protection_status =
194  	        RBD_PROTECTION_STATUS_UNPROTECTED;
195  	    }
196  	  }
197  	
198  	  snap_remove();
199  	}
200  	
201  	template <typename I>
202  	void SnapshotPurgeRequest<I>::snap_remove() {
203  	  librados::snap_t snap_id = m_snaps.back();
204  	  dout(10) << "snap_id=" << snap_id << ", "
205  	           << "snap_namespace=" << m_snap_namespace << ", "
206  	           << "snap_name=" << m_snap_name << dendl;
207  	
208  	  int r;
209  	  auto finish_op_ctx = start_lock_op(&r);
210  	  if (finish_op_ctx == nullptr) {
211  	    derr << "lost exclusive lock" << dendl;
212  	    m_ret_val = r;
213  	    close_image();
214  	    return;
215  	  }
216  	
217  	  auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
218  	      handle_snap_remove(r);
219  	      finish_op_ctx->complete(0);
220  	    });
221  	  std::shared_lock owner_locker{m_image_ctx->owner_lock};
222  	  m_image_ctx->operations->execute_snap_remove(
223  	    m_snap_namespace, m_snap_name.c_str(), ctx);
224  	}
225  	
226  	template <typename I>
227  	void SnapshotPurgeRequest<I>::handle_snap_remove(int r) {
228  	  dout(10) << "r=" << r << dendl;
229  	
230  	  if (r == -EBUSY) {
231  	    dout(10) << "snapshot in-use" << dendl;
232  	    m_ret_val = r;
233  	    close_image();
234  	    return;
235  	  } else if (r < 0) {
236  	    derr << "failed to remove snapshot: " << cpp_strerror(r) << dendl;
237  	    m_ret_val = r;
238  	    close_image();
239  	    return;
240  	  }
241  	
242  	  m_snaps.pop_back();
243  	  snap_unprotect();
244  	}
245  	
246  	template <typename I>
247  	void SnapshotPurgeRequest<I>::close_image() {
248  	  dout(10) << dendl;
249  	
250  	  m_image_ctx->state->close(create_context_callback<
251  	    SnapshotPurgeRequest<I>,
252  	    &SnapshotPurgeRequest<I>::handle_close_image>(this));
253  	}
254  	
255  	template <typename I>
256  	void SnapshotPurgeRequest<I>::handle_close_image(int r) {
257  	  dout(10) << "r=" << r << dendl;
258  	
259  	  m_image_ctx->destroy();
260  	  m_image_ctx = nullptr;
261  	
262  	  if (r < 0) {
263  	    derr << "failed to close: " << cpp_strerror(r) << dendl;
264  	    finish(r);
265  	    return;
266  	  }
267  	  finish(0);
268  	}
269  	
270  	template <typename I>
271  	void SnapshotPurgeRequest<I>::finish(int r) {
272  	  if (m_ret_val < 0) {
273  	    r = m_ret_val;
274  	  }
275  	
276  	  m_on_finish->complete(r);
277  	  delete this;
278  	}
279  	
280  	template <typename I>
281  	Context *SnapshotPurgeRequest<I>::start_lock_op(int* r) {
282  	  std::shared_lock owner_locker{m_image_ctx->owner_lock};
283  	  return m_image_ctx->exclusive_lock->start_op(r);
284  	}
285  	
286  	} // namespace image_deleter
287  	} // namespace mirror
288  	} // namespace rbd
289  	
290  	template class rbd::mirror::image_deleter::SnapshotPurgeRequest<librbd::ImageCtx>;
291