]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/Operations.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / Operations.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "cls/rbd/cls_rbd_types.h"
5#include "librbd/Operations.h"
6#include "common/dout.h"
7#include "common/errno.h"
11fdf7f2 8#include "common/perf_counters.h"
11fdf7f2 9#include "osdc/Striper.h"
7c673cae
FG
10
11#include "librbd/ExclusiveLock.h"
12#include "librbd/ImageCtx.h"
13#include "librbd/ImageState.h"
14#include "librbd/ImageWatcher.h"
15#include "librbd/ObjectMap.h"
b32b8144 16#include "librbd/Types.h"
7c673cae 17#include "librbd/Utils.h"
11fdf7f2 18#include "librbd/api/Config.h"
f67539c2 19#include "librbd/asio/ContextWQ.h"
1e59de90 20#include "librbd/io/Utils.h"
7c673cae
FG
21#include "librbd/journal/DisabledPolicy.h"
22#include "librbd/journal/StandardPolicy.h"
23#include "librbd/operation/DisableFeaturesRequest.h"
24#include "librbd/operation/EnableFeaturesRequest.h"
25#include "librbd/operation/FlattenRequest.h"
26#include "librbd/operation/MetadataRemoveRequest.h"
27#include "librbd/operation/MetadataSetRequest.h"
11fdf7f2 28#include "librbd/operation/MigrateRequest.h"
7c673cae
FG
29#include "librbd/operation/ObjectMapIterate.h"
30#include "librbd/operation/RebuildObjectMapRequest.h"
31#include "librbd/operation/RenameRequest.h"
32#include "librbd/operation/ResizeRequest.h"
33#include "librbd/operation/SnapshotCreateRequest.h"
34#include "librbd/operation/SnapshotProtectRequest.h"
35#include "librbd/operation/SnapshotRemoveRequest.h"
36#include "librbd/operation/SnapshotRenameRequest.h"
37#include "librbd/operation/SnapshotRollbackRequest.h"
38#include "librbd/operation/SnapshotUnprotectRequest.h"
39#include "librbd/operation/SnapshotLimitRequest.h"
11fdf7f2 40#include "librbd/operation/SparsifyRequest.h"
7c673cae 41#include <set>
f67539c2 42#include <boost/bind/bind.hpp>
7c673cae
FG
43#include <boost/scope_exit.hpp>
44
45#define dout_subsys ceph_subsys_rbd
46#undef dout_prefix
47#define dout_prefix *_dout << "librbd::Operations: "
48
49namespace librbd {
50
f67539c2
TL
51using namespace boost::placeholders;
52
7c673cae
FG
53namespace {
54
f67539c2
TL
55std::ostream &operator<<(std::ostream &out, const Operation &op) {
56 switch (op) {
57 case OPERATION_CHECK_OBJECT_MAP:
58 out << "check object map";
59 break;
60 case OPERATION_FLATTEN:
61 out << "flatten";
62 break;
63 case OPERATION_METADATA_UPDATE:
64 out << "metadata update";
65 break;
66 case OPERATION_MIGRATE:
67 out << "migrate";
68 break;
69 case OPERATION_REBUILD_OBJECT_MAP:
70 out << "rebuild object map";
71 break;
72 case OPERATION_RENAME:
73 out << "rename";
74 break;
75 case OPERATION_RESIZE:
76 out << "resize";
77 break;
78 case OPERATION_SNAP_CREATE:
79 out << "snap create";
80 break;
81 case OPERATION_SNAP_PROTECT:
82 out << "snap protect";
83 break;
84 case OPERATION_SNAP_REMOVE:
85 out << "snap remove";
86 break;
87 case OPERATION_SNAP_RENAME:
88 out << "snap rename";
89 break;
90 case OPERATION_SNAP_ROLLBACK:
91 out << "snap rollback";
92 break;
93 case OPERATION_SNAP_UNPROTECT:
94 out << "snap unprotect";
95 break;
96 case OPERATION_SPARSIFY:
97 out << "sparsify";
98 break;
99 case OPERATION_UPDATE_FEATURES:
100 out << "update features";
101 break;
102 default:
103 ceph_abort();
104 break;
105 }
106 return out;
107}
108
7c673cae
FG
109template <typename I>
110struct C_NotifyUpdate : public Context {
111 I &image_ctx;
112 Context *on_finish;
113 bool notified = false;
114
115 C_NotifyUpdate(I &image_ctx, Context *on_finish)
116 : image_ctx(image_ctx), on_finish(on_finish) {
117 }
118
119 void complete(int r) override {
120 CephContext *cct = image_ctx.cct;
121 if (notified) {
122 if (r == -ETIMEDOUT) {
123 // don't fail the op if a peer fails to get the update notification
124 lderr(cct) << "update notification timed-out" << dendl;
125 r = 0;
126 } else if (r == -ENOENT) {
127 // don't fail if header is missing (e.g. v1 image rename)
128 ldout(cct, 5) << "update notification on missing header" << dendl;
129 r = 0;
130 } else if (r < 0) {
131 lderr(cct) << "update notification failed: " << cpp_strerror(r)
132 << dendl;
133 }
134 Context::complete(r);
135 return;
136 }
137
138 if (r < 0) {
139 // op failed -- no need to send update notification
140 Context::complete(r);
141 return;
142 }
143
144 notified = true;
145 image_ctx.notify_update(this);
146 }
147 void finish(int r) override {
148 on_finish->complete(r);
149 }
150};
151
152template <typename I>
153struct C_InvokeAsyncRequest : public Context {
154 /**
155 * @verbatim
156 *
157 * <start>
158 * |
159 * . . . . . . | . . . . . . . . . . . . . . . . . .
160 * . . | . .
161 * . v v v .
162 * . REFRESH_IMAGE (skip if not needed) .
163 * . | .
164 * . v .
165 * . ACQUIRE_LOCK (skip if exclusive lock .
166 * . | disabled or has lock) .
167 * . | .
168 * . /--------/ \--------\ . . . . . . . . . . . . .
169 * . | | .
170 * . v v .
171 * LOCAL_REQUEST REMOTE_REQUEST
172 * | |
173 * | |
174 * \--------\ /--------/
175 * |
176 * v
177 * <finish>
178 *
179 * @endverbatim
180 */
181
182 I &image_ctx;
f67539c2 183 Operation operation;
92f5a8d4 184 exclusive_lock::OperationRequestType request_type;
7c673cae
FG
185 bool permit_snapshot;
186 boost::function<void(Context*)> local;
187 boost::function<void(Context*)> remote;
188 std::set<int> filter_error_codes;
189 Context *on_finish;
190 bool request_lock = false;
191
f67539c2 192 C_InvokeAsyncRequest(I &image_ctx, Operation operation,
92f5a8d4 193 exclusive_lock::OperationRequestType request_type,
7c673cae
FG
194 bool permit_snapshot,
195 const boost::function<void(Context*)>& local,
196 const boost::function<void(Context*)>& remote,
197 const std::set<int> &filter_error_codes,
198 Context *on_finish)
f67539c2 199 : image_ctx(image_ctx), operation(operation), request_type(request_type),
7c673cae
FG
200 permit_snapshot(permit_snapshot), local(local), remote(remote),
201 filter_error_codes(filter_error_codes), on_finish(on_finish) {
202 }
203
204 void send() {
205 send_refresh_image();
206 }
207
208 void send_refresh_image() {
209 if (!image_ctx.state->is_refresh_required()) {
210 send_acquire_exclusive_lock();
211 return;
212 }
213
214 CephContext *cct = image_ctx.cct;
215 ldout(cct, 20) << __func__ << dendl;
216
217 Context *ctx = util::create_context_callback<
218 C_InvokeAsyncRequest<I>,
219 &C_InvokeAsyncRequest<I>::handle_refresh_image>(this);
220 image_ctx.state->refresh(ctx);
221 }
222
223 void handle_refresh_image(int r) {
224 CephContext *cct = image_ctx.cct;
225 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
226
227 if (r < 0) {
228 lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl;
229 complete(r);
230 return;
231 }
232
233 send_acquire_exclusive_lock();
234 }
235
236 void send_acquire_exclusive_lock() {
237 // context can complete before owner_lock is unlocked
9f95a23c
TL
238 ceph::shared_mutex &owner_lock(image_ctx.owner_lock);
239 owner_lock.lock_shared();
240 image_ctx.image_lock.lock_shared();
7c673cae
FG
241 if (image_ctx.read_only ||
242 (!permit_snapshot && image_ctx.snap_id != CEPH_NOSNAP)) {
9f95a23c
TL
243 image_ctx.image_lock.unlock_shared();
244 owner_lock.unlock_shared();
7c673cae
FG
245 complete(-EROFS);
246 return;
247 }
9f95a23c 248 image_ctx.image_lock.unlock_shared();
7c673cae
FG
249
250 if (image_ctx.exclusive_lock == nullptr) {
251 send_local_request();
9f95a23c 252 owner_lock.unlock_shared();
7c673cae
FG
253 return;
254 } else if (image_ctx.image_watcher == nullptr) {
9f95a23c 255 owner_lock.unlock_shared();
7c673cae
FG
256 complete(-EROFS);
257 return;
258 }
259
7c673cae 260 if (image_ctx.exclusive_lock->is_lock_owner() &&
92f5a8d4 261 image_ctx.exclusive_lock->accept_request(request_type, nullptr)) {
7c673cae 262 send_local_request();
9f95a23c 263 owner_lock.unlock_shared();
7c673cae
FG
264 return;
265 }
266
267 CephContext *cct = image_ctx.cct;
268 ldout(cct, 20) << __func__ << dendl;
269
270 Context *ctx = util::create_async_context_callback(
271 image_ctx, util::create_context_callback<
9f95a23c
TL
272 C_InvokeAsyncRequest<I>,
273 &C_InvokeAsyncRequest<I>::handle_acquire_exclusive_lock>(
274 this, image_ctx.exclusive_lock));
7c673cae
FG
275
276 if (request_lock) {
277 // current lock owner doesn't support op -- try to perform
278 // the action locally
279 request_lock = false;
280 image_ctx.exclusive_lock->acquire_lock(ctx);
281 } else {
282 image_ctx.exclusive_lock->try_acquire_lock(ctx);
283 }
9f95a23c 284 owner_lock.unlock_shared();
7c673cae
FG
285 }
286
287 void handle_acquire_exclusive_lock(int r) {
288 CephContext *cct = image_ctx.cct;
289 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
290
291 if (r < 0) {
f67539c2 292 complete(r == -EBLOCKLISTED ? -EBLOCKLISTED : -EROFS);
7c673cae
FG
293 return;
294 }
295
296 // context can complete before owner_lock is unlocked
9f95a23c
TL
297 ceph::shared_mutex &owner_lock(image_ctx.owner_lock);
298 owner_lock.lock_shared();
91327a77
AA
299 if (image_ctx.exclusive_lock == nullptr ||
300 image_ctx.exclusive_lock->is_lock_owner()) {
7c673cae 301 send_local_request();
9f95a23c 302 owner_lock.unlock_shared();
7c673cae
FG
303 return;
304 }
305
306 send_remote_request();
9f95a23c 307 owner_lock.unlock_shared();
7c673cae
FG
308 }
309
310 void send_remote_request() {
9f95a23c 311 ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
7c673cae
FG
312
313 CephContext *cct = image_ctx.cct;
314 ldout(cct, 20) << __func__ << dendl;
315
11fdf7f2
TL
316 Context *ctx = util::create_async_context_callback(
317 image_ctx, util::create_context_callback<
318 C_InvokeAsyncRequest<I>,
319 &C_InvokeAsyncRequest<I>::handle_remote_request>(this));
7c673cae
FG
320 remote(ctx);
321 }
322
323 void handle_remote_request(int r) {
324 CephContext *cct = image_ctx.cct;
325 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
326
327 if (r == -EOPNOTSUPP) {
f67539c2
TL
328 ldout(cct, 5) << operation << " not supported by current lock owner"
329 << dendl;
7c673cae
FG
330 request_lock = true;
331 send_refresh_image();
332 return;
333 } else if (r != -ETIMEDOUT && r != -ERESTART) {
334 image_ctx.state->handle_update_notification();
335
336 complete(r);
337 return;
338 }
339
f67539c2 340 ldout(cct, 5) << operation << " timed out notifying lock owner" << dendl;
7c673cae
FG
341 send_refresh_image();
342 }
343
344 void send_local_request() {
f67539c2
TL
345 auto ctx = new LambdaContext(
346 [this](int r) {
347 if (r == -ERESTART) {
348 image_ctx.operations->finish_op(operation, r);
349 send_refresh_image();
350 return;
351 }
352 execute_local_request();
353 });
354
355 image_ctx.operations->start_op(operation, ctx);
356 }
357
358 void execute_local_request() {
359 std::shared_lock owner_locker{image_ctx.owner_lock};
7c673cae
FG
360
361 CephContext *cct = image_ctx.cct;
362 ldout(cct, 20) << __func__ << dendl;
363
364 Context *ctx = util::create_async_context_callback(
365 image_ctx, util::create_context_callback<
366 C_InvokeAsyncRequest<I>,
367 &C_InvokeAsyncRequest<I>::handle_local_request>(this));
368 local(ctx);
369 }
370
371 void handle_local_request(int r) {
372 CephContext *cct = image_ctx.cct;
373 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
374
f67539c2
TL
375 image_ctx.operations->finish_op(operation, r);
376
7c673cae
FG
377 if (r == -ERESTART) {
378 send_refresh_image();
379 return;
380 }
381 complete(r);
382 }
383
384 void finish(int r) override {
385 if (filter_error_codes.count(r) != 0) {
386 r = 0;
387 }
388 on_finish->complete(r);
389 }
390};
391
392template <typename I>
393bool needs_invalidate(I& image_ctx, uint64_t object_no,
394 uint8_t current_state, uint8_t new_state) {
395 if ( (current_state == OBJECT_EXISTS ||
396 current_state == OBJECT_EXISTS_CLEAN) &&
397 (new_state == OBJECT_NONEXISTENT ||
398 new_state == OBJECT_PENDING)) {
399 return false;
400 }
401 return true;
402}
403
404} // anonymous namespace
405
406template <typename I>
407Operations<I>::Operations(I &image_ctx)
f67539c2
TL
408 : m_image_ctx(image_ctx),
409 m_queue_lock(ceph::make_mutex(
410 util::unique_lock_name("librbd::Operations::m_queue_lock",
411 this))) {
412}
413
414template <typename I>
415void Operations<I>::start_op(Operation op, Context *ctx) {
416 CephContext *cct = m_image_ctx.cct;
417 ldout(cct, 20) << __func__ << ": " << op << " " << ctx << dendl;
418
419 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
420 bool requires_lock = m_image_ctx.exclusive_lock != nullptr;
421
422 ctx = util::create_async_context_callback(
423 m_image_ctx, new LambdaContext(
424 [this, op, requires_lock, ctx](int r) {
425 Context *finish_op_ctx = nullptr;
426 if (requires_lock && r == 0) {
427 std::shared_lock owner_locker{m_image_ctx.owner_lock};
428 std::shared_lock image_locker{m_image_ctx.image_lock};
429 auto exclusive_lock = m_image_ctx.exclusive_lock;
430
431 if (exclusive_lock == nullptr ||
432 (finish_op_ctx = exclusive_lock->start_op(&r)) == nullptr) {
433 ldout(m_image_ctx.cct, 20) << "lock owner lost, restarting"
434 << dendl;
435 r = -ERESTART;
436 }
437 }
438
439 ldout(m_image_ctx.cct, 20) << "start " << op << " " << ctx << dendl;
440 ctx->complete(r);
441 if (finish_op_ctx != nullptr) {
442 finish_op_ctx->complete(0);
443 }
444 }));
445
446 std::unique_lock locker{m_queue_lock};
447 if (!m_in_flight_ops.insert(op).second) {
448 ldout(cct, 20) << __func__ << ": " << op << " in flight" << dendl;
449 m_queued_ops[op].push_back(ctx);
450 return;
451 }
452
453 ctx->complete(0);
454}
455
456template <typename I>
457void Operations<I>::finish_op(Operation op, int r) {
458 CephContext *cct = m_image_ctx.cct;
459 ldout(cct, 20) << __func__ << ": " << op << " r=" << r << dendl;
460
461 std::unique_lock locker{m_queue_lock};
462 auto &queue = m_queued_ops[op];
463 if (queue.empty()) {
464 m_in_flight_ops.erase(op);
465 return;
466 }
467
468 auto ctx = queue.front();
469 queue.pop_front();
470 // propagate -ERESTART through all the queue
471 ctx->complete(r == -ERESTART ? r : 0);
7c673cae
FG
472}
473
474template <typename I>
475int Operations<I>::flatten(ProgressContext &prog_ctx) {
476 CephContext *cct = m_image_ctx.cct;
477 ldout(cct, 20) << "flatten" << dendl;
478
479 int r = m_image_ctx.state->refresh_if_required();
480 if (r < 0) {
481 return r;
482 }
483
484 if (m_image_ctx.read_only) {
485 return -EROFS;
486 }
487
488 {
9f95a23c 489 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
490 if (m_image_ctx.parent_md.spec.pool_id == -1) {
491 lderr(cct) << "image has no parent" << dendl;
492 return -EINVAL;
493 }
494 }
495
f67539c2
TL
496 uint64_t request_id = util::reserve_async_request_id();
497 r = invoke_async_request(OPERATION_FLATTEN,
92f5a8d4
TL
498 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
499 false,
7c673cae
FG
500 boost::bind(&Operations<I>::execute_flatten, this,
501 boost::ref(prog_ctx), _1),
502 boost::bind(&ImageWatcher<I>::notify_flatten,
503 m_image_ctx.image_watcher, request_id,
504 boost::ref(prog_ctx), _1));
505
506 if (r < 0 && r != -EINVAL) {
507 return r;
508 }
509 ldout(cct, 20) << "flatten finished" << dendl;
510 return 0;
511}
512
513template <typename I>
514void Operations<I>::execute_flatten(ProgressContext &prog_ctx,
515 Context *on_finish) {
9f95a23c 516 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
517 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
518 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
519
520 CephContext *cct = m_image_ctx.cct;
521 ldout(cct, 20) << "flatten" << dendl;
522
11fdf7f2 523 if (m_image_ctx.read_only || m_image_ctx.operations_disabled) {
7c673cae
FG
524 on_finish->complete(-EROFS);
525 return;
526 }
527
9f95a23c 528 m_image_ctx.image_lock.lock_shared();
7c673cae
FG
529
530 // can't flatten a non-clone
531 if (m_image_ctx.parent_md.spec.pool_id == -1) {
532 lderr(cct) << "image has no parent" << dendl;
9f95a23c 533 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
534 on_finish->complete(-EINVAL);
535 return;
536 }
537 if (m_image_ctx.snap_id != CEPH_NOSNAP) {
538 lderr(cct) << "snapshots cannot be flattened" << dendl;
9f95a23c 539 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
540 on_finish->complete(-EROFS);
541 return;
542 }
543
1e59de90
TL
544 uint64_t crypto_header_objects = Striper::get_num_objects(
545 m_image_ctx.layout,
546 m_image_ctx.get_area_size(io::ImageArea::CRYPTO_HEADER));
7c673cae 547
1e59de90
TL
548 uint64_t raw_overlap;
549 int r = m_image_ctx.get_parent_overlap(CEPH_NOSNAP, &raw_overlap);
550 ceph_assert(r == 0);
551 auto overlap = m_image_ctx.reduce_parent_overlap(raw_overlap, false);
552 uint64_t data_overlap_objects = Striper::get_num_objects(
553 m_image_ctx.layout,
554 (overlap.second == io::ImageArea::DATA ? overlap.first : 0));
7c673cae 555
9f95a23c 556 m_image_ctx.image_lock.unlock_shared();
7c673cae 557
1e59de90 558 // leave encryption header flattening to format-specific handler
7c673cae 559 operation::FlattenRequest<I> *req = new operation::FlattenRequest<I>(
1e59de90
TL
560 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
561 crypto_header_objects, data_overlap_objects, prog_ctx);
7c673cae
FG
562 req->send();
563}
564
565template <typename I>
566int Operations<I>::rebuild_object_map(ProgressContext &prog_ctx) {
567 CephContext *cct = m_image_ctx.cct;
568 ldout(cct, 10) << "rebuild_object_map" << dendl;
569
570 int r = m_image_ctx.state->refresh_if_required();
571 if (r < 0) {
572 return r;
573 }
574
f67539c2
TL
575 uint64_t request_id = util::reserve_async_request_id();
576 r = invoke_async_request(OPERATION_REBUILD_OBJECT_MAP,
92f5a8d4 577 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
7c673cae
FG
578 boost::bind(&Operations<I>::execute_rebuild_object_map,
579 this, boost::ref(prog_ctx), _1),
580 boost::bind(&ImageWatcher<I>::notify_rebuild_object_map,
581 m_image_ctx.image_watcher, request_id,
582 boost::ref(prog_ctx), _1));
583
584 ldout(cct, 10) << "rebuild object map finished" << dendl;
585 if (r < 0) {
586 return r;
587 }
588 return 0;
589}
590
591template <typename I>
592void Operations<I>::execute_rebuild_object_map(ProgressContext &prog_ctx,
593 Context *on_finish) {
9f95a23c 594 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
595 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
596 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
597
598 CephContext *cct = m_image_ctx.cct;
599 ldout(cct, 5) << this << " " << __func__ << dendl;
600
11fdf7f2 601 if (m_image_ctx.read_only || m_image_ctx.operations_disabled) {
7c673cae
FG
602 on_finish->complete(-EROFS);
603 return;
604 }
11fdf7f2 605
7c673cae
FG
606 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
607 lderr(cct) << "image must support object-map feature" << dendl;
608 on_finish->complete(-EINVAL);
609 return;
610 }
611
612 operation::RebuildObjectMapRequest<I> *req =
613 new operation::RebuildObjectMapRequest<I>(
614 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), prog_ctx);
615 req->send();
616}
617
618template <typename I>
619int Operations<I>::check_object_map(ProgressContext &prog_ctx) {
620 CephContext *cct = m_image_ctx.cct;
621 ldout(cct, 5) << this << " " << __func__ << dendl;
622 int r = m_image_ctx.state->refresh_if_required();
623 if (r < 0) {
624 return r;
625 }
626
f67539c2 627 r = invoke_async_request(OPERATION_CHECK_OBJECT_MAP,
92f5a8d4 628 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
7c673cae
FG
629 boost::bind(&Operations<I>::check_object_map, this,
630 boost::ref(prog_ctx), _1),
94b18763
FG
631 [this](Context *c) {
632 m_image_ctx.op_work_queue->queue(c, -EOPNOTSUPP);
633 });
7c673cae
FG
634
635 return r;
636}
637
638template <typename I>
639void Operations<I>::object_map_iterate(ProgressContext &prog_ctx,
640 operation::ObjectIterateWork<I> handle_mismatch,
641 Context *on_finish) {
9f95a23c 642 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
643 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
644 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
645
646 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
647 on_finish->complete(-EINVAL);
648 return;
649 }
650
651 operation::ObjectMapIterateRequest<I> *req =
652 new operation::ObjectMapIterateRequest<I>(m_image_ctx, on_finish,
653 prog_ctx, handle_mismatch);
654 req->send();
655}
656
657template <typename I>
658void Operations<I>::check_object_map(ProgressContext &prog_ctx,
659 Context *on_finish) {
660 object_map_iterate(prog_ctx, needs_invalidate, on_finish);
661}
662
663template <typename I>
664int Operations<I>::rename(const char *dstname) {
665 CephContext *cct = m_image_ctx.cct;
666 ldout(cct, 5) << this << " " << __func__ << ": dest_name=" << dstname
667 << dendl;
668
669 int r = librbd::detect_format(m_image_ctx.md_ctx, dstname, NULL, NULL);
670 if (r < 0 && r != -ENOENT) {
671 lderr(cct) << "error checking for existing image called "
672 << dstname << ":" << cpp_strerror(r) << dendl;
673 return r;
674 }
675 if (r == 0) {
676 lderr(cct) << "rbd image " << dstname << " already exists" << dendl;
677 return -EEXIST;
678 }
679
f67539c2
TL
680 uint64_t request_id = util::reserve_async_request_id();
681 r = invoke_async_request(OPERATION_RENAME,
cd265ab1
TL
682 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
683 true,
684 boost::bind(&Operations<I>::execute_rename, this,
685 dstname, _1),
686 boost::bind(&ImageWatcher<I>::notify_rename,
f67539c2
TL
687 m_image_ctx.image_watcher, request_id,
688 dstname, _1));
cd265ab1
TL
689 if (r < 0 && r != -EEXIST) {
690 return r;
7c673cae
FG
691 }
692
693 m_image_ctx.set_image_name(dstname);
694 return 0;
695}
696
697template <typename I>
698void Operations<I>::execute_rename(const std::string &dest_name,
699 Context *on_finish) {
9f95a23c 700 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae 701 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
11fdf7f2
TL
702 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
703 m_image_ctx.exclusive_lock->is_lock_owner());
704 }
705
706 if (m_image_ctx.operations_disabled) {
707 on_finish->complete(-EROFS);
708 return;
7c673cae
FG
709 }
710
7c673cae
FG
711 CephContext *cct = m_image_ctx.cct;
712 ldout(cct, 5) << this << " " << __func__ << ": dest_name=" << dest_name
713 << dendl;
714
715 if (m_image_ctx.old_format) {
cd265ab1
TL
716 m_image_ctx.image_lock.lock_shared();
717 if (m_image_ctx.name == dest_name) {
718 m_image_ctx.image_lock.unlock_shared();
719 on_finish->complete(-EEXIST);
720 return;
721 }
722 m_image_ctx.image_lock.unlock_shared();
723
7c673cae
FG
724 // unregister watch before and register back after rename
725 on_finish = new C_NotifyUpdate<I>(m_image_ctx, on_finish);
9f95a23c 726 on_finish = new LambdaContext([this, on_finish](int r) {
7c673cae
FG
727 if (m_image_ctx.old_format) {
728 m_image_ctx.image_watcher->set_oid(m_image_ctx.header_oid);
729 }
730 m_image_ctx.image_watcher->register_watch(on_finish);
731 });
9f95a23c
TL
732 on_finish = new LambdaContext([this, dest_name, on_finish](int r) {
733 std::shared_lock owner_locker{m_image_ctx.owner_lock};
7c673cae
FG
734 operation::RenameRequest<I> *req = new operation::RenameRequest<I>(
735 m_image_ctx, on_finish, dest_name);
736 req->send();
737 });
738 m_image_ctx.image_watcher->unregister_watch(on_finish);
739 return;
740 }
741 operation::RenameRequest<I> *req = new operation::RenameRequest<I>(
742 m_image_ctx, on_finish, dest_name);
743 req->send();
744}
745
746template <typename I>
747int Operations<I>::resize(uint64_t size, bool allow_shrink, ProgressContext& prog_ctx) {
748 CephContext *cct = m_image_ctx.cct;
749
9f95a23c 750 m_image_ctx.image_lock.lock_shared();
1e59de90
TL
751 uint64_t raw_size = io::util::area_to_raw_offset(m_image_ctx, size,
752 io::ImageArea::DATA);
753 ldout(cct, 5) << this << " " << __func__
754 << ": size=" << size
755 << " raw_size=" << m_image_ctx.size
756 << " new_raw_size=" << raw_size << dendl;
9f95a23c 757 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
758
759 int r = m_image_ctx.state->refresh_if_required();
760 if (r < 0) {
761 return r;
762 }
763
764 if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP) &&
1e59de90 765 !ObjectMap<>::is_compatible(m_image_ctx.layout, raw_size)) {
7c673cae
FG
766 lderr(cct) << "New size not compatible with object map" << dendl;
767 return -EINVAL;
768 }
769
f67539c2
TL
770 uint64_t request_id = util::reserve_async_request_id();
771 r = invoke_async_request(OPERATION_RESIZE,
92f5a8d4
TL
772 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
773 false,
7c673cae
FG
774 boost::bind(&Operations<I>::execute_resize, this,
775 size, allow_shrink, boost::ref(prog_ctx), _1, 0),
776 boost::bind(&ImageWatcher<I>::notify_resize,
777 m_image_ctx.image_watcher, request_id,
778 size, allow_shrink, boost::ref(prog_ctx), _1));
779
780 m_image_ctx.perfcounter->inc(l_librbd_resize);
781 ldout(cct, 2) << "resize finished" << dendl;
782 return r;
783}
784
785template <typename I>
786void Operations<I>::execute_resize(uint64_t size, bool allow_shrink, ProgressContext &prog_ctx,
787 Context *on_finish,
788 uint64_t journal_op_tid) {
9f95a23c 789 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
790 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
791 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
792
793 CephContext *cct = m_image_ctx.cct;
9f95a23c 794 m_image_ctx.image_lock.lock_shared();
1e59de90
TL
795 uint64_t raw_size = io::util::area_to_raw_offset(m_image_ctx, size,
796 io::ImageArea::DATA);
797 ldout(cct, 5) << this << " " << __func__
798 << ": size=" << size
799 << " raw_size=" << m_image_ctx.size
800 << " new_raw_size=" << raw_size << dendl;
7c673cae 801
11fdf7f2
TL
802 if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only ||
803 m_image_ctx.operations_disabled) {
9f95a23c 804 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
805 on_finish->complete(-EROFS);
806 return;
807 } else if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
9f95a23c 808 m_image_ctx.image_lock) &&
1e59de90 809 !ObjectMap<>::is_compatible(m_image_ctx.layout, raw_size)) {
9f95a23c 810 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
811 on_finish->complete(-EINVAL);
812 return;
813 }
9f95a23c 814 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
815
816 operation::ResizeRequest<I> *req = new operation::ResizeRequest<I>(
1e59de90
TL
817 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), raw_size,
818 allow_shrink, prog_ctx, journal_op_tid, false);
7c673cae
FG
819 req->send();
820}
821
822template <typename I>
823int Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
f67539c2
TL
824 const std::string& snap_name, uint64_t flags,
825 ProgressContext &prog_ctx) {
7c673cae
FG
826 if (m_image_ctx.read_only) {
827 return -EROFS;
828 }
829
830 int r = m_image_ctx.state->refresh_if_required();
831 if (r < 0) {
832 return r;
833 }
834
835 C_SaferCond ctx;
f67539c2 836 snap_create(snap_namespace, snap_name, flags, prog_ctx, &ctx);
7c673cae
FG
837 r = ctx.wait();
838
839 if (r < 0) {
840 return r;
841 }
842
843 m_image_ctx.perfcounter->inc(l_librbd_snap_create);
844 return r;
845}
846
847template <typename I>
848void Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
f67539c2
TL
849 const std::string& snap_name, uint64_t flags,
850 ProgressContext &prog_ctx, Context *on_finish) {
7c673cae
FG
851 CephContext *cct = m_image_ctx.cct;
852 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
853 << dendl;
854
855 if (m_image_ctx.read_only) {
856 on_finish->complete(-EROFS);
857 return;
858 }
859
9f95a23c 860 m_image_ctx.image_lock.lock_shared();
7c673cae 861 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP) {
9f95a23c 862 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
863 on_finish->complete(-EEXIST);
864 return;
865 }
9f95a23c 866 m_image_ctx.image_lock.unlock_shared();
7c673cae 867
f67539c2 868 uint64_t request_id = util::reserve_async_request_id();
7c673cae 869 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
f67539c2
TL
870 m_image_ctx, OPERATION_SNAP_CREATE,
871 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
7c673cae 872 boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
f67539c2 873 _1, 0, flags, boost::ref(prog_ctx)),
7c673cae 874 boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
f67539c2
TL
875 request_id, snap_namespace, snap_name, flags,
876 boost::ref(prog_ctx), _1),
7c673cae
FG
877 {-EEXIST}, on_finish);
878 req->send();
879}
880
881template <typename I>
882void Operations<I>::execute_snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
883 const std::string &snap_name,
884 Context *on_finish,
885 uint64_t journal_op_tid,
f67539c2
TL
886 uint64_t flags,
887 ProgressContext &prog_ctx) {
9f95a23c 888 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
889 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
890 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
891
892 CephContext *cct = m_image_ctx.cct;
893 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
894 << dendl;
895
11fdf7f2
TL
896 if (m_image_ctx.operations_disabled) {
897 on_finish->complete(-EROFS);
898 return;
899 }
900
9f95a23c 901 m_image_ctx.image_lock.lock_shared();
7c673cae 902 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP) {
9f95a23c 903 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
904 on_finish->complete(-EEXIST);
905 return;
906 }
9f95a23c 907 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
908
909 operation::SnapshotCreateRequest<I> *req =
910 new operation::SnapshotCreateRequest<I>(
911 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
f67539c2 912 snap_namespace, snap_name, journal_op_tid, flags, prog_ctx);
7c673cae
FG
913 req->send();
914}
915
916template <typename I>
917int Operations<I>::snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespace,
91327a77 918 const std::string& snap_name,
7c673cae
FG
919 ProgressContext& prog_ctx) {
920 CephContext *cct = m_image_ctx.cct;
921 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
922 << dendl;
923
924 int r = m_image_ctx.state->refresh_if_required();
925 if (r < 0)
926 return r;
927
b32b8144 928 C_SaferCond cond_ctx;
7c673cae 929 {
9f95a23c 930 std::shared_lock owner_locker{m_image_ctx.owner_lock};
b32b8144 931 {
9f95a23c
TL
932 // need to drop image_lock before invalidating cache
933 std::shared_lock image_locker{m_image_ctx.image_lock};
b32b8144
FG
934 if (!m_image_ctx.snap_exists) {
935 return -ENOENT;
936 }
7c673cae 937
b32b8144
FG
938 if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) {
939 return -EROFS;
940 }
941
942 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
943 if (snap_id == CEPH_NOSNAP) {
944 lderr(cct) << "No such snapshot found." << dendl;
945 return -ENOENT;
946 }
7c673cae
FG
947 }
948
92f5a8d4
TL
949 r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
950 false);
b32b8144 951 if (r < 0) {
91327a77 952 return r;
7c673cae 953 }
7c673cae 954
f67539c2
TL
955 Context *ctx = new LambdaContext(
956 [this, ctx=&cond_ctx](int r) {
957 m_image_ctx.operations->finish_op(OPERATION_SNAP_ROLLBACK, r);
958 ctx->complete(r);
959 });
960 ctx = new LambdaContext(
961 [this, snap_namespace, snap_name, &prog_ctx, ctx](int r) {
962 if (r < 0) {
963 ctx->complete(r);
964 return;
965 }
966 std::shared_lock l{m_image_ctx.owner_lock};
967 execute_snap_rollback(snap_namespace, snap_name, prog_ctx, ctx);
968 });
969
970 m_image_ctx.operations->start_op(OPERATION_SNAP_ROLLBACK, ctx);
7c673cae
FG
971 }
972
7c673cae
FG
973 r = cond_ctx.wait();
974 if (r < 0) {
975 return r;
976 }
977
978 m_image_ctx.perfcounter->inc(l_librbd_snap_rollback);
979 return r;
980}
981
982template <typename I>
983void Operations<I>::execute_snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespace,
984 const std::string &snap_name,
985 ProgressContext& prog_ctx,
986 Context *on_finish) {
9f95a23c 987 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae
FG
988 CephContext *cct = m_image_ctx.cct;
989 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
990 << dendl;
991
11fdf7f2
TL
992 if (m_image_ctx.operations_disabled) {
993 on_finish->complete(-EROFS);
994 return;
995 }
996
9f95a23c 997 m_image_ctx.image_lock.lock_shared();
7c673cae
FG
998 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
999 if (snap_id == CEPH_NOSNAP) {
1000 lderr(cct) << "No such snapshot found." << dendl;
9f95a23c 1001 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1002 on_finish->complete(-ENOENT);
1003 return;
1004 }
1005
1006 uint64_t new_size = m_image_ctx.get_image_size(snap_id);
9f95a23c 1007 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1008
1009 // async mode used for journal replay
1010 operation::SnapshotRollbackRequest<I> *request =
1011 new operation::SnapshotRollbackRequest<I>(
1012 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name,
1013 snap_id, new_size, prog_ctx);
1014 request->send();
1015}
1016
1017template <typename I>
1018int Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
91327a77 1019 const std::string& snap_name) {
7c673cae
FG
1020 if (m_image_ctx.read_only) {
1021 return -EROFS;
1022 }
1023
1024 int r = m_image_ctx.state->refresh_if_required();
1025 if (r < 0) {
1026 return r;
1027 }
1028
1029 C_SaferCond ctx;
1030 snap_remove(snap_namespace, snap_name, &ctx);
1031 r = ctx.wait();
1032
1033 if (r < 0) {
1034 return r;
1035 }
1036
1037 m_image_ctx.perfcounter->inc(l_librbd_snap_remove);
1038 return 0;
1039}
1040
1041template <typename I>
1042void Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
91327a77 1043 const std::string& snap_name,
7c673cae
FG
1044 Context *on_finish) {
1045 CephContext *cct = m_image_ctx.cct;
1046 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1047 << dendl;
1048
1049 if (m_image_ctx.read_only) {
1050 on_finish->complete(-EROFS);
1051 return;
1052 }
1053
1054 // quickly filter out duplicate ops
9f95a23c 1055 m_image_ctx.image_lock.lock_shared();
7c673cae 1056 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) == CEPH_NOSNAP) {
9f95a23c 1057 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1058 on_finish->complete(-ENOENT);
1059 return;
1060 }
1061
1062 bool proxy_op = ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 ||
1063 (m_image_ctx.features & RBD_FEATURE_JOURNALING) != 0);
9f95a23c 1064 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1065
1066 if (proxy_op) {
f67539c2 1067 uint64_t request_id = util::reserve_async_request_id();
92f5a8d4
TL
1068 auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
1069 if (cls::rbd::get_snap_namespace_type(snap_namespace) ==
1070 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
1071 request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
1072 }
7c673cae 1073 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
f67539c2
TL
1074 m_image_ctx, OPERATION_SNAP_REMOVE, request_type, true,
1075 boost::bind(&Operations<I>::execute_snap_remove, this, snap_namespace,
1076 snap_name, _1),
1077 boost::bind(&ImageWatcher<I>::notify_snap_remove,
1078 m_image_ctx.image_watcher, request_id, snap_namespace,
1079 snap_name, _1),
7c673cae
FG
1080 {-ENOENT}, on_finish);
1081 req->send();
1082 } else {
9f95a23c 1083 std::shared_lock owner_lock{m_image_ctx.owner_lock};
7c673cae
FG
1084 execute_snap_remove(snap_namespace, snap_name, on_finish);
1085 }
1086}
1087
1088template <typename I>
1089void Operations<I>::execute_snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
1090 const std::string &snap_name,
1091 Context *on_finish) {
9f95a23c 1092 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae
FG
1093 {
1094 if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
11fdf7f2
TL
1095 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1096 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
1097 }
1098 }
1099
1100 CephContext *cct = m_image_ctx.cct;
1101 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1102 << dendl;
1103
11fdf7f2
TL
1104 if (m_image_ctx.operations_disabled) {
1105 on_finish->complete(-EROFS);
1106 return;
1107 }
1108
9f95a23c 1109 m_image_ctx.image_lock.lock_shared();
7c673cae
FG
1110 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
1111 if (snap_id == CEPH_NOSNAP) {
1112 lderr(m_image_ctx.cct) << "No such snapshot found." << dendl;
9f95a23c 1113 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1114 on_finish->complete(-ENOENT);
1115 return;
1116 }
1117
1118 bool is_protected;
1119 int r = m_image_ctx.is_snap_protected(snap_id, &is_protected);
1120 if (r < 0) {
9f95a23c 1121 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1122 on_finish->complete(r);
1123 return;
1124 } else if (is_protected) {
1125 lderr(m_image_ctx.cct) << "snapshot is protected" << dendl;
9f95a23c 1126 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1127 on_finish->complete(-EBUSY);
1128 return;
1129 }
9f95a23c 1130 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1131
1132 operation::SnapshotRemoveRequest<I> *req =
1133 new operation::SnapshotRemoveRequest<I>(
1134 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
1135 snap_namespace, snap_name, snap_id);
1136 req->send();
1137}
1138
1139template <typename I>
1140int Operations<I>::snap_rename(const char *srcname, const char *dstname) {
1141 CephContext *cct = m_image_ctx.cct;
1142 ldout(cct, 5) << this << " " << __func__ << ": "
1143 << "snap_name=" << srcname << ", "
1144 << "new_snap_name=" << dstname << dendl;
1145
1146 snapid_t snap_id;
1147 if (m_image_ctx.read_only) {
1148 return -EROFS;
1149 }
1150
1151 int r = m_image_ctx.state->refresh_if_required();
1152 if (r < 0)
1153 return r;
1154
1155 {
9f95a23c 1156 std::shared_lock l{m_image_ctx.image_lock};
7c673cae
FG
1157 snap_id = m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(), srcname);
1158 if (snap_id == CEPH_NOSNAP) {
1159 return -ENOENT;
1160 }
1161 if (m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(), dstname) != CEPH_NOSNAP) {
1162 return -EEXIST;
1163 }
1164 }
1165
1166 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
f67539c2
TL
1167 uint64_t request_id = util::reserve_async_request_id();
1168 r = invoke_async_request(OPERATION_SNAP_RENAME,
92f5a8d4
TL
1169 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1170 true,
7c673cae
FG
1171 boost::bind(&Operations<I>::execute_snap_rename,
1172 this, snap_id, dstname, _1),
1173 boost::bind(&ImageWatcher<I>::notify_snap_rename,
f67539c2
TL
1174 m_image_ctx.image_watcher, request_id,
1175 snap_id, dstname, _1));
7c673cae
FG
1176 if (r < 0 && r != -EEXIST) {
1177 return r;
1178 }
1179 } else {
7c673cae 1180 C_SaferCond cond_ctx;
b32b8144 1181 {
9f95a23c 1182 std::shared_lock owner_lock{m_image_ctx.owner_lock};
b32b8144
FG
1183 execute_snap_rename(snap_id, dstname, &cond_ctx);
1184 }
7c673cae
FG
1185
1186 r = cond_ctx.wait();
1187 if (r < 0) {
1188 return r;
1189 }
1190 }
1191
1192 m_image_ctx.perfcounter->inc(l_librbd_snap_rename);
1193 return 0;
1194}
1195
1196template <typename I>
1197void Operations<I>::execute_snap_rename(const uint64_t src_snap_id,
1198 const std::string &dest_snap_name,
1199 Context *on_finish) {
9f95a23c 1200 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae 1201 if ((m_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) {
11fdf7f2
TL
1202 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1203 m_image_ctx.exclusive_lock->is_lock_owner());
1204 }
1205
1206 if (m_image_ctx.operations_disabled) {
1207 on_finish->complete(-EROFS);
1208 return;
7c673cae
FG
1209 }
1210
9f95a23c 1211 m_image_ctx.image_lock.lock_shared();
7c673cae
FG
1212 if (m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(),
1213 dest_snap_name) != CEPH_NOSNAP) {
1214 // Renaming is supported for snapshots from user namespace only.
9f95a23c 1215 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1216 on_finish->complete(-EEXIST);
1217 return;
1218 }
9f95a23c 1219 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1220
1221 CephContext *cct = m_image_ctx.cct;
1222 ldout(cct, 5) << this << " " << __func__ << ": "
1223 << "snap_id=" << src_snap_id << ", "
1224 << "new_snap_name=" << dest_snap_name << dendl;
1225
1226 operation::SnapshotRenameRequest<I> *req =
1227 new operation::SnapshotRenameRequest<I>(
1228 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), src_snap_id,
1229 dest_snap_name);
1230 req->send();
1231}
1232
1233template <typename I>
1234int Operations<I>::snap_protect(const cls::rbd::SnapshotNamespace& snap_namespace,
91327a77 1235 const std::string& snap_name) {
7c673cae
FG
1236 CephContext *cct = m_image_ctx.cct;
1237 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1238 << dendl;
1239
1240 if (m_image_ctx.read_only) {
1241 return -EROFS;
1242 }
1243
1244 if (!m_image_ctx.test_features(RBD_FEATURE_LAYERING)) {
1245 lderr(cct) << "image must support layering" << dendl;
1246 return -ENOSYS;
1247 }
1248
1249 int r = m_image_ctx.state->refresh_if_required();
1250 if (r < 0) {
1251 return r;
1252 }
1253
1254 {
9f95a23c 1255 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
1256 bool is_protected;
1257 r = m_image_ctx.is_snap_protected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1258 &is_protected);
1259 if (r < 0) {
1260 return r;
1261 }
1262
1263 if (is_protected) {
1264 return -EBUSY;
1265 }
1266 }
1267
1268 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
f67539c2
TL
1269 uint64_t request_id = util::reserve_async_request_id();
1270 r = invoke_async_request(OPERATION_SNAP_PROTECT,
92f5a8d4
TL
1271 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1272 true,
7c673cae
FG
1273 boost::bind(&Operations<I>::execute_snap_protect,
1274 this, snap_namespace, snap_name, _1),
1275 boost::bind(&ImageWatcher<I>::notify_snap_protect,
f67539c2 1276 m_image_ctx.image_watcher, request_id,
7c673cae
FG
1277 snap_namespace, snap_name, _1));
1278 if (r < 0 && r != -EBUSY) {
1279 return r;
1280 }
1281 } else {
7c673cae 1282 C_SaferCond cond_ctx;
b32b8144 1283 {
9f95a23c 1284 std::shared_lock owner_lock{m_image_ctx.owner_lock};
b32b8144
FG
1285 execute_snap_protect(snap_namespace, snap_name, &cond_ctx);
1286 }
7c673cae
FG
1287
1288 r = cond_ctx.wait();
1289 if (r < 0) {
1290 return r;
1291 }
1292 }
1293 return 0;
1294}
1295
1296template <typename I>
1297void Operations<I>::execute_snap_protect(const cls::rbd::SnapshotNamespace& snap_namespace,
1298 const std::string &snap_name,
1299 Context *on_finish) {
9f95a23c 1300 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae 1301 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
11fdf7f2
TL
1302 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1303 m_image_ctx.exclusive_lock->is_lock_owner());
1304 }
1305
1306 if (m_image_ctx.operations_disabled) {
1307 on_finish->complete(-EROFS);
1308 return;
7c673cae
FG
1309 }
1310
9f95a23c 1311 m_image_ctx.image_lock.lock_shared();
7c673cae
FG
1312 bool is_protected;
1313 int r = m_image_ctx.is_snap_protected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1314 &is_protected);
1315 if (r < 0) {
9f95a23c 1316 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1317 on_finish->complete(r);
1318 return;
1319 } else if (is_protected) {
9f95a23c 1320 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1321 on_finish->complete(-EBUSY);
1322 return;
1323 }
9f95a23c 1324 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1325
1326 CephContext *cct = m_image_ctx.cct;
1327 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1328 << dendl;
1329
1330 operation::SnapshotProtectRequest<I> *request =
1331 new operation::SnapshotProtectRequest<I>(
1332 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name);
1333 request->send();
1334}
1335
1336template <typename I>
1337int Operations<I>::snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namespace,
91327a77 1338 const std::string& snap_name) {
7c673cae
FG
1339 CephContext *cct = m_image_ctx.cct;
1340 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1341 << dendl;
1342
1343 if (m_image_ctx.read_only) {
1344 return -EROFS;
1345 }
1346
1347 int r = m_image_ctx.state->refresh_if_required();
1348 if (r < 0) {
1349 return r;
1350 }
1351
1352 {
9f95a23c 1353 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
1354 bool is_unprotected;
1355 r = m_image_ctx.is_snap_unprotected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1356 &is_unprotected);
1357 if (r < 0) {
1358 return r;
1359 }
1360
1361 if (is_unprotected) {
1362 return -EINVAL;
1363 }
1364 }
1365
1366 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
f67539c2
TL
1367 uint64_t request_id = util::reserve_async_request_id();
1368 r = invoke_async_request(OPERATION_SNAP_UNPROTECT,
92f5a8d4
TL
1369 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1370 true,
7c673cae
FG
1371 boost::bind(&Operations<I>::execute_snap_unprotect,
1372 this, snap_namespace, snap_name, _1),
1373 boost::bind(&ImageWatcher<I>::notify_snap_unprotect,
f67539c2 1374 m_image_ctx.image_watcher, request_id,
7c673cae
FG
1375 snap_namespace, snap_name, _1));
1376 if (r < 0 && r != -EINVAL) {
1377 return r;
1378 }
1379 } else {
7c673cae 1380 C_SaferCond cond_ctx;
b32b8144 1381 {
9f95a23c 1382 std::shared_lock owner_lock{m_image_ctx.owner_lock};
b32b8144
FG
1383 execute_snap_unprotect(snap_namespace, snap_name, &cond_ctx);
1384 }
7c673cae
FG
1385
1386 r = cond_ctx.wait();
1387 if (r < 0) {
1388 return r;
1389 }
1390 }
1391 return 0;
1392}
1393
1394template <typename I>
1395void Operations<I>::execute_snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namespace,
1396 const std::string &snap_name,
1397 Context *on_finish) {
9f95a23c 1398 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae 1399 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
11fdf7f2
TL
1400 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1401 m_image_ctx.exclusive_lock->is_lock_owner());
1402 }
1403
1404 if (m_image_ctx.operations_disabled) {
1405 on_finish->complete(-EROFS);
1406 return;
7c673cae
FG
1407 }
1408
9f95a23c 1409 m_image_ctx.image_lock.lock_shared();
7c673cae
FG
1410 bool is_unprotected;
1411 int r = m_image_ctx.is_snap_unprotected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1412 &is_unprotected);
1413 if (r < 0) {
9f95a23c 1414 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1415 on_finish->complete(r);
1416 return;
1417 } else if (is_unprotected) {
9f95a23c 1418 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1419 on_finish->complete(-EINVAL);
1420 return;
1421 }
9f95a23c 1422 m_image_ctx.image_lock.unlock_shared();
7c673cae
FG
1423
1424 CephContext *cct = m_image_ctx.cct;
1425 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1426 << dendl;
1427
1428 operation::SnapshotUnprotectRequest<I> *request =
1429 new operation::SnapshotUnprotectRequest<I>(
1430 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name);
1431 request->send();
1432}
1433
1434template <typename I>
1435int Operations<I>::snap_set_limit(uint64_t limit) {
1436 CephContext *cct = m_image_ctx.cct;
1437 ldout(cct, 5) << this << " " << __func__ << ": limit=" << limit << dendl;
1438
1439 if (m_image_ctx.read_only) {
1440 return -EROFS;
1441 }
1442
1443 int r = m_image_ctx.state->refresh_if_required();
1444 if (r < 0) {
1445 return r;
1446 }
1447
b32b8144 1448 C_SaferCond limit_ctx;
7c673cae 1449 {
9f95a23c 1450 std::shared_lock owner_lock{m_image_ctx.owner_lock};
92f5a8d4
TL
1451 r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1452 true);
b32b8144
FG
1453 if (r < 0) {
1454 return r;
7c673cae
FG
1455 }
1456
1457 execute_snap_set_limit(limit, &limit_ctx);
7c673cae
FG
1458 }
1459
b32b8144 1460 r = limit_ctx.wait();
7c673cae
FG
1461 return r;
1462}
1463
1464template <typename I>
1465void Operations<I>::execute_snap_set_limit(const uint64_t limit,
1466 Context *on_finish) {
9f95a23c 1467 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae
FG
1468
1469 CephContext *cct = m_image_ctx.cct;
1470 ldout(cct, 5) << this << " " << __func__ << ": limit=" << limit
1471 << dendl;
1472
1473 operation::SnapshotLimitRequest<I> *request =
1474 new operation::SnapshotLimitRequest<I>(m_image_ctx, on_finish, limit);
1475 request->send();
1476}
1477
1478template <typename I>
1479int Operations<I>::update_features(uint64_t features, bool enabled) {
1480 CephContext *cct = m_image_ctx.cct;
1481 ldout(cct, 5) << this << " " << __func__ << ": features=" << features
1482 << ", enabled=" << enabled << dendl;
1483
1484 int r = m_image_ctx.state->refresh_if_required();
1485 if (r < 0) {
1486 return r;
1487 }
1488
1489 if (m_image_ctx.read_only) {
1490 return -EROFS;
1491 } else if (m_image_ctx.old_format) {
1492 lderr(cct) << "old-format images do not support features" << dendl;
1493 return -EINVAL;
1494 }
1495
1496 uint64_t disable_mask = (RBD_FEATURES_MUTABLE |
1497 RBD_FEATURES_DISABLE_ONLY);
1498 if ((enabled && (features & RBD_FEATURES_MUTABLE) != features) ||
9f95a23c
TL
1499 (!enabled && (features & disable_mask) != features) ||
1500 ((features & ~RBD_FEATURES_MUTABLE_INTERNAL) != features)) {
7c673cae
FG
1501 lderr(cct) << "cannot update immutable features" << dendl;
1502 return -EINVAL;
1503 }
11fdf7f2
TL
1504
1505 bool set_object_map = (features & RBD_FEATURE_OBJECT_MAP) == RBD_FEATURE_OBJECT_MAP;
1506 bool set_fast_diff = (features & RBD_FEATURE_FAST_DIFF) == RBD_FEATURE_FAST_DIFF;
1507 bool exist_fast_diff = (m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0;
1508 bool exist_object_map = (m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0;
1509
1510 if ((enabled && ((set_object_map && !exist_fast_diff) || (set_fast_diff && !exist_object_map)))
1511 || (!enabled && (set_object_map && exist_fast_diff))) {
1512 features |= (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF);
1513 }
1514
7c673cae
FG
1515 if (features == 0) {
1516 lderr(cct) << "update requires at least one feature" << dendl;
1517 return -EINVAL;
1518 }
1519 {
9f95a23c 1520 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
1521 if (enabled && (features & m_image_ctx.features) != 0) {
1522 lderr(cct) << "one or more requested features are already enabled"
1523 << dendl;
1524 return -EINVAL;
1525 }
1526 if (!enabled && (features & ~m_image_ctx.features) != 0) {
1527 lderr(cct) << "one or more requested features are already disabled"
1528 << dendl;
1529 return -EINVAL;
1530 }
1531 }
1532
1533 // if disabling journaling, avoid attempting to open the journal
1534 // when acquiring the exclusive lock in case the journal is corrupt
1535 bool disabling_journal = false;
1536 if (!enabled && ((features & RBD_FEATURE_JOURNALING) != 0)) {
9f95a23c 1537 std::unique_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
1538 m_image_ctx.set_journal_policy(new journal::DisabledPolicy());
1539 disabling_journal = true;
1540 }
1541 BOOST_SCOPE_EXIT_ALL( (this)(disabling_journal) ) {
1542 if (disabling_journal) {
9f95a23c 1543 std::unique_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
1544 m_image_ctx.set_journal_policy(
1545 new journal::StandardPolicy<I>(&m_image_ctx));
1546 }
1547 };
1548
91327a77
AA
1549 // The journal options are not passed to the lock owner in the
1550 // update features request. Therefore, if journaling is being
1551 // enabled, the lock should be locally acquired instead of
1552 // attempting to send the request to the peer.
1553 if (enabled && (features & RBD_FEATURE_JOURNALING) != 0) {
1554 C_SaferCond cond_ctx;
1555 {
9f95a23c 1556 std::shared_lock owner_lock{m_image_ctx.owner_lock};
92f5a8d4
TL
1557 r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1558 true);
91327a77
AA
1559 if (r < 0) {
1560 return r;
1561 }
1562
1563 execute_update_features(features, enabled, &cond_ctx, 0);
1564 }
1565
1566 r = cond_ctx.wait();
1567 } else {
f67539c2
TL
1568 uint64_t request_id = util::reserve_async_request_id();
1569 r = invoke_async_request(OPERATION_UPDATE_FEATURES,
92f5a8d4
TL
1570 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1571 false,
91327a77
AA
1572 boost::bind(&Operations<I>::execute_update_features,
1573 this, features, enabled, _1, 0),
1574 boost::bind(&ImageWatcher<I>::notify_update_features,
f67539c2
TL
1575 m_image_ctx.image_watcher, request_id,
1576 features, enabled, _1));
91327a77 1577 }
7c673cae
FG
1578 ldout(cct, 2) << "update_features finished" << dendl;
1579 return r;
1580}
1581
1582template <typename I>
1583void Operations<I>::execute_update_features(uint64_t features, bool enabled,
1584 Context *on_finish,
1585 uint64_t journal_op_tid) {
9f95a23c 1586 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
1587 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1588 m_image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
1589
1590 CephContext *cct = m_image_ctx.cct;
1591 ldout(cct, 5) << this << " " << __func__ << ": features=" << features
1592 << ", enabled=" << enabled << dendl;
1593
11fdf7f2
TL
1594 if (m_image_ctx.operations_disabled) {
1595 on_finish->complete(-EROFS);
1596 return;
1597 }
1598
7c673cae
FG
1599 if (enabled) {
1600 operation::EnableFeaturesRequest<I> *req =
1601 new operation::EnableFeaturesRequest<I>(
1602 m_image_ctx, on_finish, journal_op_tid, features);
1603 req->send();
1604 } else {
1605 operation::DisableFeaturesRequest<I> *req =
1606 new operation::DisableFeaturesRequest<I>(
1607 m_image_ctx, on_finish, journal_op_tid, features, false);
1608 req->send();
1609 }
1610}
1611
1612template <typename I>
1613int Operations<I>::metadata_set(const std::string &key,
1614 const std::string &value) {
1615 CephContext *cct = m_image_ctx.cct;
1616 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << ", value="
1617 << value << dendl;
1618
b32b8144
FG
1619 std::string config_key;
1620 bool config_override = util::is_metadata_config_override(key, &config_key);
1621 if (config_override) {
7c673cae 1622 // validate config setting
11fdf7f2
TL
1623 if (!librbd::api::Config<I>::is_option_name(&m_image_ctx, config_key)) {
1624 lderr(cct) << "validation for " << key
1625 << " failed: not allowed image level override" << dendl;
1626 return -EINVAL;
1627 }
1628 int r = ConfigProxy{false}.set_val(config_key.c_str(), value);
7c673cae
FG
1629 if (r < 0) {
1630 return r;
1631 }
1632 }
1633
1634 int r = m_image_ctx.state->refresh_if_required();
1635 if (r < 0) {
1636 return r;
1637 }
1638
1639 if (m_image_ctx.read_only) {
1640 return -EROFS;
1641 }
1642
f67539c2
TL
1643 uint64_t request_id = util::reserve_async_request_id();
1644 r = invoke_async_request(OPERATION_METADATA_UPDATE,
1645 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1646 false,
1647 boost::bind(&Operations<I>::execute_metadata_set,
1648 this, key, value, _1),
1649 boost::bind(&ImageWatcher<I>::notify_metadata_set,
1650 m_image_ctx.image_watcher, request_id,
1651 key, value, _1));
b32b8144 1652
b32b8144
FG
1653 if (config_override && r >= 0) {
1654 // apply new config key immediately
1655 r = m_image_ctx.state->refresh_if_required();
7c673cae
FG
1656 }
1657
f67539c2 1658 ldout(cct, 20) << "metadata_set finished" << dendl;
7c673cae
FG
1659 return r;
1660}
1661
1662template <typename I>
1663void Operations<I>::execute_metadata_set(const std::string &key,
1664 const std::string &value,
1665 Context *on_finish) {
9f95a23c 1666 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae
FG
1667
1668 CephContext *cct = m_image_ctx.cct;
1669 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << ", value="
1670 << value << dendl;
1671
11fdf7f2
TL
1672 if (m_image_ctx.operations_disabled) {
1673 on_finish->complete(-EROFS);
1674 return;
1675 }
1676
7c673cae 1677 operation::MetadataSetRequest<I> *request =
b32b8144
FG
1678 new operation::MetadataSetRequest<I>(m_image_ctx,
1679 new C_NotifyUpdate<I>(m_image_ctx, on_finish),
1680 key, value);
7c673cae
FG
1681 request->send();
1682}
1683
1684template <typename I>
1685int Operations<I>::metadata_remove(const std::string &key) {
1686 CephContext *cct = m_image_ctx.cct;
1687 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
1688
7c673cae
FG
1689 int r = m_image_ctx.state->refresh_if_required();
1690 if (r < 0) {
1691 return r;
1692 }
1693
1694 if (m_image_ctx.read_only) {
1695 return -EROFS;
1696 }
1697
d2e6a577
FG
1698 std::string value;
1699 r = cls_client::metadata_get(&m_image_ctx.md_ctx, m_image_ctx.header_oid, key, &value);
1700 if(r < 0)
1701 return r;
1702
f67539c2
TL
1703 uint64_t request_id = util::reserve_async_request_id();
1704 r = invoke_async_request(OPERATION_METADATA_UPDATE,
1705 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1706 false,
1707 boost::bind(&Operations<I>::execute_metadata_remove,
1708 this, key, _1),
1709 boost::bind(&ImageWatcher<I>::notify_metadata_remove,
1710 m_image_ctx.image_watcher, request_id,
1711 key, _1));
1712 if (r == -ENOENT) {
1713 r = 0;
b32b8144
FG
1714 }
1715
b32b8144
FG
1716 std::string config_key;
1717 if (util::is_metadata_config_override(key, &config_key) && r >= 0) {
1718 // apply new config key immediately
1719 r = m_image_ctx.state->refresh_if_required();
7c673cae
FG
1720 }
1721
f67539c2 1722 ldout(cct, 20) << "metadata_remove finished" << dendl;
7c673cae
FG
1723 return r;
1724}
1725
1726template <typename I>
1727void Operations<I>::execute_metadata_remove(const std::string &key,
1728 Context *on_finish) {
9f95a23c 1729 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
7c673cae
FG
1730
1731 CephContext *cct = m_image_ctx.cct;
1732 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
1733
11fdf7f2
TL
1734 if (m_image_ctx.operations_disabled) {
1735 on_finish->complete(-EROFS);
1736 return;
1737 }
1738
7c673cae 1739 operation::MetadataRemoveRequest<I> *request =
b32b8144
FG
1740 new operation::MetadataRemoveRequest<I>(
1741 m_image_ctx,
1742 new C_NotifyUpdate<I>(m_image_ctx, on_finish), key);
7c673cae
FG
1743 request->send();
1744}
1745
11fdf7f2
TL
1746template <typename I>
1747int Operations<I>::migrate(ProgressContext &prog_ctx) {
1748 CephContext *cct = m_image_ctx.cct;
1749 ldout(cct, 20) << "migrate" << dendl;
1750
1751 int r = m_image_ctx.state->refresh_if_required();
1752 if (r < 0) {
1753 return r;
1754 }
1755
1756 if (m_image_ctx.read_only) {
1757 return -EROFS;
1758 }
1759
1760 {
9f95a23c 1761 std::shared_lock image_locker{m_image_ctx.image_lock};
11fdf7f2
TL
1762 if (m_image_ctx.migration_info.empty()) {
1763 lderr(cct) << "image has no migrating parent" << dendl;
1764 return -EINVAL;
1765 }
1766 }
1767
f67539c2
TL
1768 uint64_t request_id = util::reserve_async_request_id();
1769 r = invoke_async_request(OPERATION_MIGRATE,
92f5a8d4
TL
1770 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1771 false,
11fdf7f2
TL
1772 boost::bind(&Operations<I>::execute_migrate, this,
1773 boost::ref(prog_ctx), _1),
1774 boost::bind(&ImageWatcher<I>::notify_migrate,
1775 m_image_ctx.image_watcher, request_id,
1776 boost::ref(prog_ctx), _1));
1777
1778 if (r < 0 && r != -EINVAL) {
1779 return r;
1780 }
1781 ldout(cct, 20) << "migrate finished" << dendl;
1782 return 0;
1783}
1784
1785template <typename I>
1786void Operations<I>::execute_migrate(ProgressContext &prog_ctx,
1787 Context *on_finish) {
9f95a23c 1788 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
1789 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1790 m_image_ctx.exclusive_lock->is_lock_owner());
1791
1792 CephContext *cct = m_image_ctx.cct;
1793 ldout(cct, 20) << "migrate" << dendl;
1794
1795 if (m_image_ctx.read_only || m_image_ctx.operations_disabled) {
1796 on_finish->complete(-EROFS);
1797 return;
1798 }
1799
9f95a23c 1800 m_image_ctx.image_lock.lock_shared();
11fdf7f2
TL
1801
1802 if (m_image_ctx.migration_info.empty()) {
1803 lderr(cct) << "image has no migrating parent" << dendl;
9f95a23c 1804 m_image_ctx.image_lock.unlock_shared();
11fdf7f2
TL
1805 on_finish->complete(-EINVAL);
1806 return;
1807 }
1808 if (m_image_ctx.snap_id != CEPH_NOSNAP) {
1809 lderr(cct) << "snapshots cannot be migrated" << dendl;
9f95a23c 1810 m_image_ctx.image_lock.unlock_shared();
11fdf7f2
TL
1811 on_finish->complete(-EROFS);
1812 return;
1813 }
1814
9f95a23c 1815 m_image_ctx.image_lock.unlock_shared();
11fdf7f2
TL
1816
1817 operation::MigrateRequest<I> *req = new operation::MigrateRequest<I>(
1818 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), prog_ctx);
1819 req->send();
1820}
1821
1822template <typename I>
1823int Operations<I>::sparsify(size_t sparse_size, ProgressContext &prog_ctx) {
1824 CephContext *cct = m_image_ctx.cct;
1825 ldout(cct, 20) << "sparsify" << dendl;
92f5a8d4 1826
11fdf7f2
TL
1827 if (sparse_size < 4096 || sparse_size > m_image_ctx.get_object_size() ||
1828 (sparse_size & (sparse_size - 1)) != 0) {
1829 lderr(cct) << "sparse size should be power of two not less than 4096"
1830 << " and not larger image object size" << dendl;
1831 return -EINVAL;
1832 }
1833
f67539c2
TL
1834 uint64_t request_id = util::reserve_async_request_id();
1835 int r = invoke_async_request(OPERATION_SPARSIFY,
92f5a8d4
TL
1836 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
1837 false,
11fdf7f2
TL
1838 boost::bind(&Operations<I>::execute_sparsify,
1839 this, sparse_size,
1840 boost::ref(prog_ctx), _1),
1841 boost::bind(&ImageWatcher<I>::notify_sparsify,
1842 m_image_ctx.image_watcher,
1843 request_id, sparse_size,
1844 boost::ref(prog_ctx), _1));
1845 if (r < 0 && r != -EINVAL) {
1846 return r;
1847 }
1848 ldout(cct, 20) << "resparsify finished" << dendl;
1849 return 0;
1850}
1851
1852template <typename I>
1853void Operations<I>::execute_sparsify(size_t sparse_size,
1854 ProgressContext &prog_ctx,
1855 Context *on_finish) {
9f95a23c 1856 ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
11fdf7f2
TL
1857 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1858 m_image_ctx.exclusive_lock->is_lock_owner());
1859
1860 CephContext *cct = m_image_ctx.cct;
1861 ldout(cct, 20) << "sparsify" << dendl;
1862
1863 if (m_image_ctx.operations_disabled) {
1864 on_finish->complete(-EROFS);
1865 return;
1866 }
1867
1868 auto req = new operation::SparsifyRequest<I>(
1869 m_image_ctx, sparse_size, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
1870 prog_ctx);
1871 req->send();
1872}
1873
7c673cae 1874template <typename I>
92f5a8d4
TL
1875int Operations<I>::prepare_image_update(
1876 exclusive_lock::OperationRequestType request_type, bool request_lock) {
9f95a23c 1877 ceph_assert(ceph_mutex_is_rlocked(m_image_ctx.owner_lock));
b32b8144 1878 if (m_image_ctx.image_watcher == nullptr) {
7c673cae
FG
1879 return -EROFS;
1880 }
1881
1882 // need to upgrade to a write lock
7c673cae 1883 C_SaferCond ctx;
9f95a23c 1884 m_image_ctx.owner_lock.unlock_shared();
b32b8144 1885 bool attempting_lock = false;
7c673cae 1886 {
9f95a23c 1887 std::unique_lock owner_locker{m_image_ctx.owner_lock};
7c673cae
FG
1888 if (m_image_ctx.exclusive_lock != nullptr &&
1889 (!m_image_ctx.exclusive_lock->is_lock_owner() ||
92f5a8d4 1890 !m_image_ctx.exclusive_lock->accept_request(request_type, nullptr))) {
b32b8144
FG
1891
1892 attempting_lock = true;
1893 m_image_ctx.exclusive_lock->block_requests(0);
1894
1895 if (request_lock) {
1896 m_image_ctx.exclusive_lock->acquire_lock(&ctx);
1897 } else {
1898 m_image_ctx.exclusive_lock->try_acquire_lock(&ctx);
1899 }
7c673cae
FG
1900 }
1901 }
1902
31f18b77 1903 int r = 0;
b32b8144 1904 if (attempting_lock) {
7c673cae
FG
1905 r = ctx.wait();
1906 }
b32b8144 1907
9f95a23c 1908 m_image_ctx.owner_lock.lock_shared();
b32b8144
FG
1909 if (attempting_lock && m_image_ctx.exclusive_lock != nullptr) {
1910 m_image_ctx.exclusive_lock->unblock_requests();
1911 }
7c673cae 1912
91327a77
AA
1913 if (r == -EAGAIN || r == -EBUSY) {
1914 r = 0;
1915 }
b32b8144
FG
1916 if (r < 0) {
1917 return r;
1918 } else if (m_image_ctx.exclusive_lock != nullptr &&
1919 !m_image_ctx.exclusive_lock->is_lock_owner()) {
91327a77 1920 return m_image_ctx.exclusive_lock->get_unlocked_op_error();
b32b8144
FG
1921 }
1922
1923 return 0;
7c673cae
FG
1924}
1925
1926template <typename I>
92f5a8d4 1927int Operations<I>::invoke_async_request(
f67539c2 1928 Operation op, exclusive_lock::OperationRequestType request_type,
92f5a8d4
TL
1929 bool permit_snapshot, const boost::function<void(Context*)>& local_request,
1930 const boost::function<void(Context*)>& remote_request) {
7c673cae 1931 C_SaferCond ctx;
f67539c2 1932 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx, op,
7c673cae
FG
1933 request_type,
1934 permit_snapshot,
1935 local_request,
1936 remote_request,
1937 {}, &ctx);
1938 req->send();
1939 return ctx.wait();
1940}
1941
1942} // namespace librbd
1943
1944template class librbd::Operations<librbd::ImageCtx>;