]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/Operations.cc
update sources to v12.2.5
[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"
8#include "common/WorkQueue.h"
9
10#include "librbd/ExclusiveLock.h"
11#include "librbd/ImageCtx.h"
12#include "librbd/ImageState.h"
13#include "librbd/ImageWatcher.h"
14#include "librbd/ObjectMap.h"
b32b8144 15#include "librbd/Types.h"
7c673cae
FG
16#include "librbd/Utils.h"
17#include "librbd/journal/DisabledPolicy.h"
18#include "librbd/journal/StandardPolicy.h"
19#include "librbd/operation/DisableFeaturesRequest.h"
20#include "librbd/operation/EnableFeaturesRequest.h"
21#include "librbd/operation/FlattenRequest.h"
22#include "librbd/operation/MetadataRemoveRequest.h"
23#include "librbd/operation/MetadataSetRequest.h"
24#include "librbd/operation/ObjectMapIterate.h"
25#include "librbd/operation/RebuildObjectMapRequest.h"
26#include "librbd/operation/RenameRequest.h"
27#include "librbd/operation/ResizeRequest.h"
28#include "librbd/operation/SnapshotCreateRequest.h"
29#include "librbd/operation/SnapshotProtectRequest.h"
30#include "librbd/operation/SnapshotRemoveRequest.h"
31#include "librbd/operation/SnapshotRenameRequest.h"
32#include "librbd/operation/SnapshotRollbackRequest.h"
33#include "librbd/operation/SnapshotUnprotectRequest.h"
34#include "librbd/operation/SnapshotLimitRequest.h"
35#include <set>
36#include <boost/bind.hpp>
37#include <boost/scope_exit.hpp>
38
39#define dout_subsys ceph_subsys_rbd
40#undef dout_prefix
41#define dout_prefix *_dout << "librbd::Operations: "
42
43namespace librbd {
44
45namespace {
46
47template <typename I>
48struct C_NotifyUpdate : public Context {
49 I &image_ctx;
50 Context *on_finish;
51 bool notified = false;
52
53 C_NotifyUpdate(I &image_ctx, Context *on_finish)
54 : image_ctx(image_ctx), on_finish(on_finish) {
55 }
56
57 void complete(int r) override {
58 CephContext *cct = image_ctx.cct;
59 if (notified) {
60 if (r == -ETIMEDOUT) {
61 // don't fail the op if a peer fails to get the update notification
62 lderr(cct) << "update notification timed-out" << dendl;
63 r = 0;
64 } else if (r == -ENOENT) {
65 // don't fail if header is missing (e.g. v1 image rename)
66 ldout(cct, 5) << "update notification on missing header" << dendl;
67 r = 0;
68 } else if (r < 0) {
69 lderr(cct) << "update notification failed: " << cpp_strerror(r)
70 << dendl;
71 }
72 Context::complete(r);
73 return;
74 }
75
76 if (r < 0) {
77 // op failed -- no need to send update notification
78 Context::complete(r);
79 return;
80 }
81
82 notified = true;
83 image_ctx.notify_update(this);
84 }
85 void finish(int r) override {
86 on_finish->complete(r);
87 }
88};
89
90template <typename I>
91struct C_InvokeAsyncRequest : public Context {
92 /**
93 * @verbatim
94 *
95 * <start>
96 * |
97 * . . . . . . | . . . . . . . . . . . . . . . . . .
98 * . . | . .
99 * . v v v .
100 * . REFRESH_IMAGE (skip if not needed) .
101 * . | .
102 * . v .
103 * . ACQUIRE_LOCK (skip if exclusive lock .
104 * . | disabled or has lock) .
105 * . | .
106 * . /--------/ \--------\ . . . . . . . . . . . . .
107 * . | | .
108 * . v v .
109 * LOCAL_REQUEST REMOTE_REQUEST
110 * | |
111 * | |
112 * \--------\ /--------/
113 * |
114 * v
115 * <finish>
116 *
117 * @endverbatim
118 */
119
120 I &image_ctx;
121 std::string request_type;
122 bool permit_snapshot;
123 boost::function<void(Context*)> local;
124 boost::function<void(Context*)> remote;
125 std::set<int> filter_error_codes;
126 Context *on_finish;
127 bool request_lock = false;
128
129 C_InvokeAsyncRequest(I &image_ctx, const std::string& request_type,
130 bool permit_snapshot,
131 const boost::function<void(Context*)>& local,
132 const boost::function<void(Context*)>& remote,
133 const std::set<int> &filter_error_codes,
134 Context *on_finish)
135 : image_ctx(image_ctx), request_type(request_type),
136 permit_snapshot(permit_snapshot), local(local), remote(remote),
137 filter_error_codes(filter_error_codes), on_finish(on_finish) {
138 }
139
140 void send() {
141 send_refresh_image();
142 }
143
144 void send_refresh_image() {
145 if (!image_ctx.state->is_refresh_required()) {
146 send_acquire_exclusive_lock();
147 return;
148 }
149
150 CephContext *cct = image_ctx.cct;
151 ldout(cct, 20) << __func__ << dendl;
152
153 Context *ctx = util::create_context_callback<
154 C_InvokeAsyncRequest<I>,
155 &C_InvokeAsyncRequest<I>::handle_refresh_image>(this);
156 image_ctx.state->refresh(ctx);
157 }
158
159 void handle_refresh_image(int r) {
160 CephContext *cct = image_ctx.cct;
161 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
162
163 if (r < 0) {
164 lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl;
165 complete(r);
166 return;
167 }
168
169 send_acquire_exclusive_lock();
170 }
171
172 void send_acquire_exclusive_lock() {
173 // context can complete before owner_lock is unlocked
174 RWLock &owner_lock(image_ctx.owner_lock);
175 owner_lock.get_read();
176 image_ctx.snap_lock.get_read();
177 if (image_ctx.read_only ||
178 (!permit_snapshot && image_ctx.snap_id != CEPH_NOSNAP)) {
179 image_ctx.snap_lock.put_read();
180 owner_lock.put_read();
181 complete(-EROFS);
182 return;
183 }
184 image_ctx.snap_lock.put_read();
185
186 if (image_ctx.exclusive_lock == nullptr) {
187 send_local_request();
188 owner_lock.put_read();
189 return;
190 } else if (image_ctx.image_watcher == nullptr) {
191 owner_lock.put_read();
192 complete(-EROFS);
193 return;
194 }
195
7c673cae 196 if (image_ctx.exclusive_lock->is_lock_owner() &&
31f18b77 197 image_ctx.exclusive_lock->accept_requests()) {
7c673cae
FG
198 send_local_request();
199 owner_lock.put_read();
200 return;
201 }
202
203 CephContext *cct = image_ctx.cct;
204 ldout(cct, 20) << __func__ << dendl;
205
206 Context *ctx = util::create_async_context_callback(
207 image_ctx, util::create_context_callback<
208 C_InvokeAsyncRequest<I>,
209 &C_InvokeAsyncRequest<I>::handle_acquire_exclusive_lock>(this));
210
211 if (request_lock) {
212 // current lock owner doesn't support op -- try to perform
213 // the action locally
214 request_lock = false;
215 image_ctx.exclusive_lock->acquire_lock(ctx);
216 } else {
217 image_ctx.exclusive_lock->try_acquire_lock(ctx);
218 }
219 owner_lock.put_read();
220 }
221
222 void handle_acquire_exclusive_lock(int r) {
223 CephContext *cct = image_ctx.cct;
224 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
225
226 if (r < 0) {
227 complete(-EROFS);
228 return;
229 }
230
231 // context can complete before owner_lock is unlocked
232 RWLock &owner_lock(image_ctx.owner_lock);
233 owner_lock.get_read();
234 if (image_ctx.exclusive_lock->is_lock_owner()) {
235 send_local_request();
236 owner_lock.put_read();
237 return;
238 }
239
240 send_remote_request();
241 owner_lock.put_read();
242 }
243
244 void send_remote_request() {
245 assert(image_ctx.owner_lock.is_locked());
246
247 CephContext *cct = image_ctx.cct;
248 ldout(cct, 20) << __func__ << dendl;
249
250 Context *ctx = util::create_context_callback<
251 C_InvokeAsyncRequest<I>, &C_InvokeAsyncRequest<I>::handle_remote_request>(
252 this);
253 remote(ctx);
254 }
255
256 void handle_remote_request(int r) {
257 CephContext *cct = image_ctx.cct;
258 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
259
260 if (r == -EOPNOTSUPP) {
261 ldout(cct, 5) << request_type << " not supported by current lock owner"
262 << dendl;
263 request_lock = true;
264 send_refresh_image();
265 return;
266 } else if (r != -ETIMEDOUT && r != -ERESTART) {
267 image_ctx.state->handle_update_notification();
268
269 complete(r);
270 return;
271 }
272
273 ldout(cct, 5) << request_type << " timed out notifying lock owner"
274 << dendl;
275 send_refresh_image();
276 }
277
278 void send_local_request() {
279 assert(image_ctx.owner_lock.is_locked());
280
281 CephContext *cct = image_ctx.cct;
282 ldout(cct, 20) << __func__ << dendl;
283
284 Context *ctx = util::create_async_context_callback(
285 image_ctx, util::create_context_callback<
286 C_InvokeAsyncRequest<I>,
287 &C_InvokeAsyncRequest<I>::handle_local_request>(this));
288 local(ctx);
289 }
290
291 void handle_local_request(int r) {
292 CephContext *cct = image_ctx.cct;
293 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
294
295 if (r == -ERESTART) {
296 send_refresh_image();
297 return;
298 }
299 complete(r);
300 }
301
302 void finish(int r) override {
303 if (filter_error_codes.count(r) != 0) {
304 r = 0;
305 }
306 on_finish->complete(r);
307 }
308};
309
310template <typename I>
311bool needs_invalidate(I& image_ctx, uint64_t object_no,
312 uint8_t current_state, uint8_t new_state) {
313 if ( (current_state == OBJECT_EXISTS ||
314 current_state == OBJECT_EXISTS_CLEAN) &&
315 (new_state == OBJECT_NONEXISTENT ||
316 new_state == OBJECT_PENDING)) {
317 return false;
318 }
319 return true;
320}
321
322} // anonymous namespace
323
324template <typename I>
325Operations<I>::Operations(I &image_ctx)
326 : m_image_ctx(image_ctx), m_async_request_seq(0) {
327}
328
329template <typename I>
330int Operations<I>::flatten(ProgressContext &prog_ctx) {
331 CephContext *cct = m_image_ctx.cct;
332 ldout(cct, 20) << "flatten" << dendl;
333
334 int r = m_image_ctx.state->refresh_if_required();
335 if (r < 0) {
336 return r;
337 }
338
339 if (m_image_ctx.read_only) {
340 return -EROFS;
341 }
342
343 {
344 RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
345 if (m_image_ctx.parent_md.spec.pool_id == -1) {
346 lderr(cct) << "image has no parent" << dendl;
347 return -EINVAL;
348 }
349 }
350
351 uint64_t request_id = ++m_async_request_seq;
352 r = invoke_async_request("flatten", false,
353 boost::bind(&Operations<I>::execute_flatten, this,
354 boost::ref(prog_ctx), _1),
355 boost::bind(&ImageWatcher<I>::notify_flatten,
356 m_image_ctx.image_watcher, request_id,
357 boost::ref(prog_ctx), _1));
358
359 if (r < 0 && r != -EINVAL) {
360 return r;
361 }
362 ldout(cct, 20) << "flatten finished" << dendl;
363 return 0;
364}
365
366template <typename I>
367void Operations<I>::execute_flatten(ProgressContext &prog_ctx,
368 Context *on_finish) {
369 assert(m_image_ctx.owner_lock.is_locked());
370 assert(m_image_ctx.exclusive_lock == nullptr ||
371 m_image_ctx.exclusive_lock->is_lock_owner());
372
373 CephContext *cct = m_image_ctx.cct;
374 ldout(cct, 20) << "flatten" << dendl;
375
376 if (m_image_ctx.read_only) {
377 on_finish->complete(-EROFS);
378 return;
379 }
380
381 m_image_ctx.snap_lock.get_read();
382 m_image_ctx.parent_lock.get_read();
383
384 // can't flatten a non-clone
385 if (m_image_ctx.parent_md.spec.pool_id == -1) {
386 lderr(cct) << "image has no parent" << dendl;
387 m_image_ctx.parent_lock.put_read();
388 m_image_ctx.snap_lock.put_read();
389 on_finish->complete(-EINVAL);
390 return;
391 }
392 if (m_image_ctx.snap_id != CEPH_NOSNAP) {
393 lderr(cct) << "snapshots cannot be flattened" << dendl;
394 m_image_ctx.parent_lock.put_read();
395 m_image_ctx.snap_lock.put_read();
396 on_finish->complete(-EROFS);
397 return;
398 }
399
400 ::SnapContext snapc = m_image_ctx.snapc;
401 assert(m_image_ctx.parent != NULL);
402
403 uint64_t overlap;
404 int r = m_image_ctx.get_parent_overlap(CEPH_NOSNAP, &overlap);
405 assert(r == 0);
406 assert(overlap <= m_image_ctx.size);
407
408 uint64_t object_size = m_image_ctx.get_object_size();
409 uint64_t overlap_objects = Striper::get_num_objects(m_image_ctx.layout,
410 overlap);
411
412 m_image_ctx.parent_lock.put_read();
413 m_image_ctx.snap_lock.put_read();
414
415 operation::FlattenRequest<I> *req = new operation::FlattenRequest<I>(
416 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), object_size,
417 overlap_objects, snapc, prog_ctx);
418 req->send();
419}
420
421template <typename I>
422int Operations<I>::rebuild_object_map(ProgressContext &prog_ctx) {
423 CephContext *cct = m_image_ctx.cct;
424 ldout(cct, 10) << "rebuild_object_map" << dendl;
425
426 int r = m_image_ctx.state->refresh_if_required();
427 if (r < 0) {
428 return r;
429 }
430
431 uint64_t request_id = ++m_async_request_seq;
432 r = invoke_async_request("rebuild object map", true,
433 boost::bind(&Operations<I>::execute_rebuild_object_map,
434 this, boost::ref(prog_ctx), _1),
435 boost::bind(&ImageWatcher<I>::notify_rebuild_object_map,
436 m_image_ctx.image_watcher, request_id,
437 boost::ref(prog_ctx), _1));
438
439 ldout(cct, 10) << "rebuild object map finished" << dendl;
440 if (r < 0) {
441 return r;
442 }
443 return 0;
444}
445
446template <typename I>
447void Operations<I>::execute_rebuild_object_map(ProgressContext &prog_ctx,
448 Context *on_finish) {
449 assert(m_image_ctx.owner_lock.is_locked());
450 assert(m_image_ctx.exclusive_lock == nullptr ||
451 m_image_ctx.exclusive_lock->is_lock_owner());
452
453 CephContext *cct = m_image_ctx.cct;
454 ldout(cct, 5) << this << " " << __func__ << dendl;
455
456 if (m_image_ctx.read_only) {
457 on_finish->complete(-EROFS);
458 return;
459 }
460 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
461 lderr(cct) << "image must support object-map feature" << dendl;
462 on_finish->complete(-EINVAL);
463 return;
464 }
465
466 operation::RebuildObjectMapRequest<I> *req =
467 new operation::RebuildObjectMapRequest<I>(
468 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), prog_ctx);
469 req->send();
470}
471
472template <typename I>
473int Operations<I>::check_object_map(ProgressContext &prog_ctx) {
474 CephContext *cct = m_image_ctx.cct;
475 ldout(cct, 5) << this << " " << __func__ << dendl;
476 int r = m_image_ctx.state->refresh_if_required();
477 if (r < 0) {
478 return r;
479 }
480
481 r = invoke_async_request("check object map", true,
482 boost::bind(&Operations<I>::check_object_map, this,
483 boost::ref(prog_ctx), _1),
94b18763
FG
484 [this](Context *c) {
485 m_image_ctx.op_work_queue->queue(c, -EOPNOTSUPP);
486 });
7c673cae
FG
487
488 return r;
489}
490
491template <typename I>
492void Operations<I>::object_map_iterate(ProgressContext &prog_ctx,
493 operation::ObjectIterateWork<I> handle_mismatch,
494 Context *on_finish) {
495 assert(m_image_ctx.owner_lock.is_locked());
496 assert(m_image_ctx.exclusive_lock == nullptr ||
497 m_image_ctx.exclusive_lock->is_lock_owner());
498
499 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
500 on_finish->complete(-EINVAL);
501 return;
502 }
503
504 operation::ObjectMapIterateRequest<I> *req =
505 new operation::ObjectMapIterateRequest<I>(m_image_ctx, on_finish,
506 prog_ctx, handle_mismatch);
507 req->send();
508}
509
510template <typename I>
511void Operations<I>::check_object_map(ProgressContext &prog_ctx,
512 Context *on_finish) {
513 object_map_iterate(prog_ctx, needs_invalidate, on_finish);
514}
515
516template <typename I>
517int Operations<I>::rename(const char *dstname) {
518 CephContext *cct = m_image_ctx.cct;
519 ldout(cct, 5) << this << " " << __func__ << ": dest_name=" << dstname
520 << dendl;
521
522 int r = librbd::detect_format(m_image_ctx.md_ctx, dstname, NULL, NULL);
523 if (r < 0 && r != -ENOENT) {
524 lderr(cct) << "error checking for existing image called "
525 << dstname << ":" << cpp_strerror(r) << dendl;
526 return r;
527 }
528 if (r == 0) {
529 lderr(cct) << "rbd image " << dstname << " already exists" << dendl;
530 return -EEXIST;
531 }
532
533 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
534 r = invoke_async_request("rename", true,
535 boost::bind(&Operations<I>::execute_rename, this,
536 dstname, _1),
537 boost::bind(&ImageWatcher<I>::notify_rename,
538 m_image_ctx.image_watcher, dstname,
539 _1));
540 if (r < 0 && r != -EEXIST) {
541 return r;
542 }
543 } else {
7c673cae 544 C_SaferCond cond_ctx;
b32b8144
FG
545 {
546 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
547 execute_rename(dstname, &cond_ctx);
548 }
7c673cae
FG
549
550 r = cond_ctx.wait();
551 if (r < 0) {
552 return r;
553 }
554 }
555
556 m_image_ctx.set_image_name(dstname);
557 return 0;
558}
559
560template <typename I>
561void Operations<I>::execute_rename(const std::string &dest_name,
562 Context *on_finish) {
563 assert(m_image_ctx.owner_lock.is_locked());
564 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
565 assert(m_image_ctx.exclusive_lock == nullptr ||
566 m_image_ctx.exclusive_lock->is_lock_owner());
567 }
568
569 m_image_ctx.snap_lock.get_read();
570 if (m_image_ctx.name == dest_name) {
571 m_image_ctx.snap_lock.put_read();
572 on_finish->complete(-EEXIST);
573 return;
574 }
575 m_image_ctx.snap_lock.put_read();
576
577 CephContext *cct = m_image_ctx.cct;
578 ldout(cct, 5) << this << " " << __func__ << ": dest_name=" << dest_name
579 << dendl;
580
581 if (m_image_ctx.old_format) {
582 // unregister watch before and register back after rename
583 on_finish = new C_NotifyUpdate<I>(m_image_ctx, on_finish);
584 on_finish = new FunctionContext([this, on_finish](int r) {
585 if (m_image_ctx.old_format) {
586 m_image_ctx.image_watcher->set_oid(m_image_ctx.header_oid);
587 }
588 m_image_ctx.image_watcher->register_watch(on_finish);
589 });
590 on_finish = new FunctionContext([this, dest_name, on_finish](int r) {
b32b8144 591 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
7c673cae
FG
592 operation::RenameRequest<I> *req = new operation::RenameRequest<I>(
593 m_image_ctx, on_finish, dest_name);
594 req->send();
595 });
596 m_image_ctx.image_watcher->unregister_watch(on_finish);
597 return;
598 }
599 operation::RenameRequest<I> *req = new operation::RenameRequest<I>(
600 m_image_ctx, on_finish, dest_name);
601 req->send();
602}
603
604template <typename I>
605int Operations<I>::resize(uint64_t size, bool allow_shrink, ProgressContext& prog_ctx) {
606 CephContext *cct = m_image_ctx.cct;
607
608 m_image_ctx.snap_lock.get_read();
609 ldout(cct, 5) << this << " " << __func__ << ": "
610 << "size=" << m_image_ctx.size << ", "
611 << "new_size=" << size << dendl;
612 m_image_ctx.snap_lock.put_read();
613
614 int r = m_image_ctx.state->refresh_if_required();
615 if (r < 0) {
616 return r;
617 }
618
619 if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP) &&
620 !ObjectMap<>::is_compatible(m_image_ctx.layout, size)) {
621 lderr(cct) << "New size not compatible with object map" << dendl;
622 return -EINVAL;
623 }
624
625 uint64_t request_id = ++m_async_request_seq;
626 r = invoke_async_request("resize", false,
627 boost::bind(&Operations<I>::execute_resize, this,
628 size, allow_shrink, boost::ref(prog_ctx), _1, 0),
629 boost::bind(&ImageWatcher<I>::notify_resize,
630 m_image_ctx.image_watcher, request_id,
631 size, allow_shrink, boost::ref(prog_ctx), _1));
632
633 m_image_ctx.perfcounter->inc(l_librbd_resize);
634 ldout(cct, 2) << "resize finished" << dendl;
635 return r;
636}
637
638template <typename I>
639void Operations<I>::execute_resize(uint64_t size, bool allow_shrink, ProgressContext &prog_ctx,
640 Context *on_finish,
641 uint64_t journal_op_tid) {
642 assert(m_image_ctx.owner_lock.is_locked());
643 assert(m_image_ctx.exclusive_lock == nullptr ||
644 m_image_ctx.exclusive_lock->is_lock_owner());
645
646 CephContext *cct = m_image_ctx.cct;
647 m_image_ctx.snap_lock.get_read();
648 ldout(cct, 5) << this << " " << __func__ << ": "
649 << "size=" << m_image_ctx.size << ", "
650 << "new_size=" << size << dendl;
651
652 if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) {
653 m_image_ctx.snap_lock.put_read();
654 on_finish->complete(-EROFS);
655 return;
656 } else if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
657 m_image_ctx.snap_lock) &&
658 !ObjectMap<>::is_compatible(m_image_ctx.layout, size)) {
659 m_image_ctx.snap_lock.put_read();
660 on_finish->complete(-EINVAL);
661 return;
662 }
663 m_image_ctx.snap_lock.put_read();
664
665 operation::ResizeRequest<I> *req = new operation::ResizeRequest<I>(
666 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), size, allow_shrink,
667 prog_ctx, journal_op_tid, false);
668 req->send();
669}
670
671template <typename I>
672int Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
673 const char *snap_name) {
674 if (m_image_ctx.read_only) {
675 return -EROFS;
676 }
677
678 int r = m_image_ctx.state->refresh_if_required();
679 if (r < 0) {
680 return r;
681 }
682
683 C_SaferCond ctx;
684 snap_create(snap_namespace, snap_name, &ctx);
685 r = ctx.wait();
686
687 if (r < 0) {
688 return r;
689 }
690
691 m_image_ctx.perfcounter->inc(l_librbd_snap_create);
692 return r;
693}
694
695template <typename I>
696void Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
697 const char *snap_name,
698 Context *on_finish) {
699 CephContext *cct = m_image_ctx.cct;
700 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
701 << dendl;
702
703 if (m_image_ctx.read_only) {
704 on_finish->complete(-EROFS);
705 return;
706 }
707
708 m_image_ctx.snap_lock.get_read();
709 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP) {
710 m_image_ctx.snap_lock.put_read();
711 on_finish->complete(-EEXIST);
712 return;
713 }
714 m_image_ctx.snap_lock.put_read();
715
716 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
717 m_image_ctx, "snap_create", true,
718 boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
719 _1, 0, false),
720 boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
721 snap_namespace, snap_name, _1),
722 {-EEXIST}, on_finish);
723 req->send();
724}
725
726template <typename I>
727void Operations<I>::execute_snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
728 const std::string &snap_name,
729 Context *on_finish,
730 uint64_t journal_op_tid,
731 bool skip_object_map) {
732 assert(m_image_ctx.owner_lock.is_locked());
733 assert(m_image_ctx.exclusive_lock == nullptr ||
734 m_image_ctx.exclusive_lock->is_lock_owner());
735
736 CephContext *cct = m_image_ctx.cct;
737 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
738 << dendl;
739
740 m_image_ctx.snap_lock.get_read();
741 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP) {
742 m_image_ctx.snap_lock.put_read();
743 on_finish->complete(-EEXIST);
744 return;
745 }
746 m_image_ctx.snap_lock.put_read();
747
748 operation::SnapshotCreateRequest<I> *req =
749 new operation::SnapshotCreateRequest<I>(
750 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
751 snap_namespace, snap_name, journal_op_tid, skip_object_map);
752 req->send();
753}
754
755template <typename I>
756int Operations<I>::snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespace,
757 const char *snap_name,
758 ProgressContext& prog_ctx) {
759 CephContext *cct = m_image_ctx.cct;
760 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
761 << dendl;
762
763 int r = m_image_ctx.state->refresh_if_required();
764 if (r < 0)
765 return r;
766
b32b8144 767 C_SaferCond cond_ctx;
7c673cae 768 {
b32b8144
FG
769 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
770 {
771 // need to drop snap_lock before invalidating cache
772 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
773 if (!m_image_ctx.snap_exists) {
774 return -ENOENT;
775 }
7c673cae 776
b32b8144
FG
777 if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) {
778 return -EROFS;
779 }
780
781 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
782 if (snap_id == CEPH_NOSNAP) {
783 lderr(cct) << "No such snapshot found." << dendl;
784 return -ENOENT;
785 }
7c673cae
FG
786 }
787
b32b8144
FG
788 r = prepare_image_update(false);
789 if (r < 0) {
790 return -EROFS;
7c673cae 791 }
7c673cae 792
b32b8144 793 execute_snap_rollback(snap_namespace, snap_name, prog_ctx, &cond_ctx);
7c673cae
FG
794 }
795
7c673cae
FG
796 r = cond_ctx.wait();
797 if (r < 0) {
798 return r;
799 }
800
801 m_image_ctx.perfcounter->inc(l_librbd_snap_rollback);
802 return r;
803}
804
805template <typename I>
806void Operations<I>::execute_snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespace,
807 const std::string &snap_name,
808 ProgressContext& prog_ctx,
809 Context *on_finish) {
810 assert(m_image_ctx.owner_lock.is_locked());
811 CephContext *cct = m_image_ctx.cct;
812 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
813 << dendl;
814
815 m_image_ctx.snap_lock.get_read();
816 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
817 if (snap_id == CEPH_NOSNAP) {
818 lderr(cct) << "No such snapshot found." << dendl;
819 m_image_ctx.snap_lock.put_read();
820 on_finish->complete(-ENOENT);
821 return;
822 }
823
824 uint64_t new_size = m_image_ctx.get_image_size(snap_id);
825 m_image_ctx.snap_lock.put_read();
826
827 // async mode used for journal replay
828 operation::SnapshotRollbackRequest<I> *request =
829 new operation::SnapshotRollbackRequest<I>(
830 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name,
831 snap_id, new_size, prog_ctx);
832 request->send();
833}
834
835template <typename I>
836int Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
837 const char *snap_name) {
838 if (m_image_ctx.read_only) {
839 return -EROFS;
840 }
841
842 int r = m_image_ctx.state->refresh_if_required();
843 if (r < 0) {
844 return r;
845 }
846
847 C_SaferCond ctx;
848 snap_remove(snap_namespace, snap_name, &ctx);
849 r = ctx.wait();
850
851 if (r < 0) {
852 return r;
853 }
854
855 m_image_ctx.perfcounter->inc(l_librbd_snap_remove);
856 return 0;
857}
858
859template <typename I>
860void Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
861 const char *snap_name,
862 Context *on_finish) {
863 CephContext *cct = m_image_ctx.cct;
864 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
865 << dendl;
866
867 if (m_image_ctx.read_only) {
868 on_finish->complete(-EROFS);
869 return;
870 }
871
872 // quickly filter out duplicate ops
873 m_image_ctx.snap_lock.get_read();
874 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) == CEPH_NOSNAP) {
875 m_image_ctx.snap_lock.put_read();
876 on_finish->complete(-ENOENT);
877 return;
878 }
879
880 bool proxy_op = ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 ||
881 (m_image_ctx.features & RBD_FEATURE_JOURNALING) != 0);
882 m_image_ctx.snap_lock.put_read();
883
884 if (proxy_op) {
885 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
886 m_image_ctx, "snap_remove", true,
887 boost::bind(&Operations<I>::execute_snap_remove, this, snap_namespace, snap_name, _1),
888 boost::bind(&ImageWatcher<I>::notify_snap_remove, m_image_ctx.image_watcher,
889 snap_namespace, snap_name, _1),
890 {-ENOENT}, on_finish);
891 req->send();
892 } else {
893 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
894 execute_snap_remove(snap_namespace, snap_name, on_finish);
895 }
896}
897
898template <typename I>
899void Operations<I>::execute_snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
900 const std::string &snap_name,
901 Context *on_finish) {
902 assert(m_image_ctx.owner_lock.is_locked());
903 {
904 if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
905 assert(m_image_ctx.exclusive_lock == nullptr ||
906 m_image_ctx.exclusive_lock->is_lock_owner());
907 }
908 }
909
910 CephContext *cct = m_image_ctx.cct;
911 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
912 << dendl;
913
914 m_image_ctx.snap_lock.get_read();
915 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
916 if (snap_id == CEPH_NOSNAP) {
917 lderr(m_image_ctx.cct) << "No such snapshot found." << dendl;
918 m_image_ctx.snap_lock.put_read();
919 on_finish->complete(-ENOENT);
920 return;
921 }
922
923 bool is_protected;
924 int r = m_image_ctx.is_snap_protected(snap_id, &is_protected);
925 if (r < 0) {
926 m_image_ctx.snap_lock.put_read();
927 on_finish->complete(r);
928 return;
929 } else if (is_protected) {
930 lderr(m_image_ctx.cct) << "snapshot is protected" << dendl;
931 m_image_ctx.snap_lock.put_read();
932 on_finish->complete(-EBUSY);
933 return;
934 }
935 m_image_ctx.snap_lock.put_read();
936
937 operation::SnapshotRemoveRequest<I> *req =
938 new operation::SnapshotRemoveRequest<I>(
939 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
940 snap_namespace, snap_name, snap_id);
941 req->send();
942}
943
944template <typename I>
945int Operations<I>::snap_rename(const char *srcname, const char *dstname) {
946 CephContext *cct = m_image_ctx.cct;
947 ldout(cct, 5) << this << " " << __func__ << ": "
948 << "snap_name=" << srcname << ", "
949 << "new_snap_name=" << dstname << dendl;
950
951 snapid_t snap_id;
952 if (m_image_ctx.read_only) {
953 return -EROFS;
954 }
955
956 int r = m_image_ctx.state->refresh_if_required();
957 if (r < 0)
958 return r;
959
960 {
961 RWLock::RLocker l(m_image_ctx.snap_lock);
962 snap_id = m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(), srcname);
963 if (snap_id == CEPH_NOSNAP) {
964 return -ENOENT;
965 }
966 if (m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(), dstname) != CEPH_NOSNAP) {
967 return -EEXIST;
968 }
969 }
970
971 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
972 r = invoke_async_request("snap_rename", true,
973 boost::bind(&Operations<I>::execute_snap_rename,
974 this, snap_id, dstname, _1),
975 boost::bind(&ImageWatcher<I>::notify_snap_rename,
976 m_image_ctx.image_watcher, snap_id,
977 dstname, _1));
978 if (r < 0 && r != -EEXIST) {
979 return r;
980 }
981 } else {
7c673cae 982 C_SaferCond cond_ctx;
b32b8144
FG
983 {
984 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
985 execute_snap_rename(snap_id, dstname, &cond_ctx);
986 }
7c673cae
FG
987
988 r = cond_ctx.wait();
989 if (r < 0) {
990 return r;
991 }
992 }
993
994 m_image_ctx.perfcounter->inc(l_librbd_snap_rename);
995 return 0;
996}
997
998template <typename I>
999void Operations<I>::execute_snap_rename(const uint64_t src_snap_id,
1000 const std::string &dest_snap_name,
1001 Context *on_finish) {
1002 assert(m_image_ctx.owner_lock.is_locked());
1003 if ((m_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) {
1004 assert(m_image_ctx.exclusive_lock == nullptr ||
1005 m_image_ctx.exclusive_lock->is_lock_owner());
1006 }
1007
1008 m_image_ctx.snap_lock.get_read();
1009 if (m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(),
1010 dest_snap_name) != CEPH_NOSNAP) {
1011 // Renaming is supported for snapshots from user namespace only.
1012 m_image_ctx.snap_lock.put_read();
1013 on_finish->complete(-EEXIST);
1014 return;
1015 }
1016 m_image_ctx.snap_lock.put_read();
1017
1018 CephContext *cct = m_image_ctx.cct;
1019 ldout(cct, 5) << this << " " << __func__ << ": "
1020 << "snap_id=" << src_snap_id << ", "
1021 << "new_snap_name=" << dest_snap_name << dendl;
1022
1023 operation::SnapshotRenameRequest<I> *req =
1024 new operation::SnapshotRenameRequest<I>(
1025 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), src_snap_id,
1026 dest_snap_name);
1027 req->send();
1028}
1029
1030template <typename I>
1031int Operations<I>::snap_protect(const cls::rbd::SnapshotNamespace& snap_namespace,
1032 const char *snap_name) {
1033 CephContext *cct = m_image_ctx.cct;
1034 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1035 << dendl;
1036
1037 if (m_image_ctx.read_only) {
1038 return -EROFS;
1039 }
1040
1041 if (!m_image_ctx.test_features(RBD_FEATURE_LAYERING)) {
1042 lderr(cct) << "image must support layering" << dendl;
1043 return -ENOSYS;
1044 }
1045
1046 int r = m_image_ctx.state->refresh_if_required();
1047 if (r < 0) {
1048 return r;
1049 }
1050
1051 {
1052 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
1053 bool is_protected;
1054 r = m_image_ctx.is_snap_protected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1055 &is_protected);
1056 if (r < 0) {
1057 return r;
1058 }
1059
1060 if (is_protected) {
1061 return -EBUSY;
1062 }
1063 }
1064
1065 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1066 r = invoke_async_request("snap_protect", true,
1067 boost::bind(&Operations<I>::execute_snap_protect,
1068 this, snap_namespace, snap_name, _1),
1069 boost::bind(&ImageWatcher<I>::notify_snap_protect,
1070 m_image_ctx.image_watcher,
1071 snap_namespace, snap_name, _1));
1072 if (r < 0 && r != -EBUSY) {
1073 return r;
1074 }
1075 } else {
7c673cae 1076 C_SaferCond cond_ctx;
b32b8144
FG
1077 {
1078 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1079 execute_snap_protect(snap_namespace, snap_name, &cond_ctx);
1080 }
7c673cae
FG
1081
1082 r = cond_ctx.wait();
1083 if (r < 0) {
1084 return r;
1085 }
1086 }
1087 return 0;
1088}
1089
1090template <typename I>
1091void Operations<I>::execute_snap_protect(const cls::rbd::SnapshotNamespace& snap_namespace,
1092 const std::string &snap_name,
1093 Context *on_finish) {
1094 assert(m_image_ctx.owner_lock.is_locked());
1095 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1096 assert(m_image_ctx.exclusive_lock == nullptr ||
1097 m_image_ctx.exclusive_lock->is_lock_owner());
1098 }
1099
1100 m_image_ctx.snap_lock.get_read();
1101 bool is_protected;
1102 int r = m_image_ctx.is_snap_protected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1103 &is_protected);
1104 if (r < 0) {
1105 m_image_ctx.snap_lock.put_read();
1106 on_finish->complete(r);
1107 return;
1108 } else if (is_protected) {
1109 m_image_ctx.snap_lock.put_read();
1110 on_finish->complete(-EBUSY);
1111 return;
1112 }
1113 m_image_ctx.snap_lock.put_read();
1114
1115 CephContext *cct = m_image_ctx.cct;
1116 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1117 << dendl;
1118
1119 operation::SnapshotProtectRequest<I> *request =
1120 new operation::SnapshotProtectRequest<I>(
1121 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name);
1122 request->send();
1123}
1124
1125template <typename I>
1126int Operations<I>::snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namespace,
1127 const char *snap_name) {
1128 CephContext *cct = m_image_ctx.cct;
1129 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1130 << dendl;
1131
1132 if (m_image_ctx.read_only) {
1133 return -EROFS;
1134 }
1135
1136 int r = m_image_ctx.state->refresh_if_required();
1137 if (r < 0) {
1138 return r;
1139 }
1140
1141 {
1142 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
1143 bool is_unprotected;
1144 r = m_image_ctx.is_snap_unprotected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1145 &is_unprotected);
1146 if (r < 0) {
1147 return r;
1148 }
1149
1150 if (is_unprotected) {
1151 return -EINVAL;
1152 }
1153 }
1154
1155 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1156 r = invoke_async_request("snap_unprotect", true,
1157 boost::bind(&Operations<I>::execute_snap_unprotect,
1158 this, snap_namespace, snap_name, _1),
1159 boost::bind(&ImageWatcher<I>::notify_snap_unprotect,
1160 m_image_ctx.image_watcher,
1161 snap_namespace, snap_name, _1));
1162 if (r < 0 && r != -EINVAL) {
1163 return r;
1164 }
1165 } else {
7c673cae 1166 C_SaferCond cond_ctx;
b32b8144
FG
1167 {
1168 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1169 execute_snap_unprotect(snap_namespace, snap_name, &cond_ctx);
1170 }
7c673cae
FG
1171
1172 r = cond_ctx.wait();
1173 if (r < 0) {
1174 return r;
1175 }
1176 }
1177 return 0;
1178}
1179
1180template <typename I>
1181void Operations<I>::execute_snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namespace,
1182 const std::string &snap_name,
1183 Context *on_finish) {
1184 assert(m_image_ctx.owner_lock.is_locked());
1185 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1186 assert(m_image_ctx.exclusive_lock == nullptr ||
1187 m_image_ctx.exclusive_lock->is_lock_owner());
1188 }
1189
1190 m_image_ctx.snap_lock.get_read();
1191 bool is_unprotected;
1192 int r = m_image_ctx.is_snap_unprotected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1193 &is_unprotected);
1194 if (r < 0) {
1195 m_image_ctx.snap_lock.put_read();
1196 on_finish->complete(r);
1197 return;
1198 } else if (is_unprotected) {
1199 m_image_ctx.snap_lock.put_read();
1200 on_finish->complete(-EINVAL);
1201 return;
1202 }
1203 m_image_ctx.snap_lock.put_read();
1204
1205 CephContext *cct = m_image_ctx.cct;
1206 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1207 << dendl;
1208
1209 operation::SnapshotUnprotectRequest<I> *request =
1210 new operation::SnapshotUnprotectRequest<I>(
1211 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name);
1212 request->send();
1213}
1214
1215template <typename I>
1216int Operations<I>::snap_set_limit(uint64_t limit) {
1217 CephContext *cct = m_image_ctx.cct;
1218 ldout(cct, 5) << this << " " << __func__ << ": limit=" << limit << dendl;
1219
1220 if (m_image_ctx.read_only) {
1221 return -EROFS;
1222 }
1223
1224 int r = m_image_ctx.state->refresh_if_required();
1225 if (r < 0) {
1226 return r;
1227 }
1228
b32b8144 1229 C_SaferCond limit_ctx;
7c673cae
FG
1230 {
1231 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
b32b8144
FG
1232 r = prepare_image_update(true);
1233 if (r < 0) {
1234 return r;
7c673cae
FG
1235 }
1236
1237 execute_snap_set_limit(limit, &limit_ctx);
7c673cae
FG
1238 }
1239
b32b8144 1240 r = limit_ctx.wait();
7c673cae
FG
1241 return r;
1242}
1243
1244template <typename I>
1245void Operations<I>::execute_snap_set_limit(const uint64_t limit,
1246 Context *on_finish) {
1247 assert(m_image_ctx.owner_lock.is_locked());
1248
1249 CephContext *cct = m_image_ctx.cct;
1250 ldout(cct, 5) << this << " " << __func__ << ": limit=" << limit
1251 << dendl;
1252
1253 operation::SnapshotLimitRequest<I> *request =
1254 new operation::SnapshotLimitRequest<I>(m_image_ctx, on_finish, limit);
1255 request->send();
1256}
1257
1258template <typename I>
1259int Operations<I>::update_features(uint64_t features, bool enabled) {
1260 CephContext *cct = m_image_ctx.cct;
1261 ldout(cct, 5) << this << " " << __func__ << ": features=" << features
1262 << ", enabled=" << enabled << dendl;
1263
1264 int r = m_image_ctx.state->refresh_if_required();
1265 if (r < 0) {
1266 return r;
1267 }
1268
1269 if (m_image_ctx.read_only) {
1270 return -EROFS;
1271 } else if (m_image_ctx.old_format) {
1272 lderr(cct) << "old-format images do not support features" << dendl;
1273 return -EINVAL;
1274 }
1275
1276 uint64_t disable_mask = (RBD_FEATURES_MUTABLE |
1277 RBD_FEATURES_DISABLE_ONLY);
1278 if ((enabled && (features & RBD_FEATURES_MUTABLE) != features) ||
1279 (!enabled && (features & disable_mask) != features)) {
1280 lderr(cct) << "cannot update immutable features" << dendl;
1281 return -EINVAL;
1282 }
1283 if (features == 0) {
1284 lderr(cct) << "update requires at least one feature" << dendl;
1285 return -EINVAL;
1286 }
1287 {
1288 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
1289 if (enabled && (features & m_image_ctx.features) != 0) {
1290 lderr(cct) << "one or more requested features are already enabled"
1291 << dendl;
1292 return -EINVAL;
1293 }
1294 if (!enabled && (features & ~m_image_ctx.features) != 0) {
1295 lderr(cct) << "one or more requested features are already disabled"
1296 << dendl;
1297 return -EINVAL;
1298 }
1299 }
1300
1301 // if disabling journaling, avoid attempting to open the journal
1302 // when acquiring the exclusive lock in case the journal is corrupt
1303 bool disabling_journal = false;
1304 if (!enabled && ((features & RBD_FEATURE_JOURNALING) != 0)) {
1305 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
1306 m_image_ctx.set_journal_policy(new journal::DisabledPolicy());
1307 disabling_journal = true;
1308 }
1309 BOOST_SCOPE_EXIT_ALL( (this)(disabling_journal) ) {
1310 if (disabling_journal) {
1311 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
1312 m_image_ctx.set_journal_policy(
1313 new journal::StandardPolicy<I>(&m_image_ctx));
1314 }
1315 };
1316
1317 r = invoke_async_request("update_features", false,
1318 boost::bind(&Operations<I>::execute_update_features,
1319 this, features, enabled, _1, 0),
1320 boost::bind(&ImageWatcher<I>::notify_update_features,
1321 m_image_ctx.image_watcher, features,
1322 enabled, _1));
1323 ldout(cct, 2) << "update_features finished" << dendl;
1324 return r;
1325}
1326
1327template <typename I>
1328void Operations<I>::execute_update_features(uint64_t features, bool enabled,
1329 Context *on_finish,
1330 uint64_t journal_op_tid) {
1331 assert(m_image_ctx.owner_lock.is_locked());
1332 assert(m_image_ctx.exclusive_lock == nullptr ||
1333 m_image_ctx.exclusive_lock->is_lock_owner());
1334
1335 CephContext *cct = m_image_ctx.cct;
1336 ldout(cct, 5) << this << " " << __func__ << ": features=" << features
1337 << ", enabled=" << enabled << dendl;
1338
1339 if (enabled) {
1340 operation::EnableFeaturesRequest<I> *req =
1341 new operation::EnableFeaturesRequest<I>(
1342 m_image_ctx, on_finish, journal_op_tid, features);
1343 req->send();
1344 } else {
1345 operation::DisableFeaturesRequest<I> *req =
1346 new operation::DisableFeaturesRequest<I>(
1347 m_image_ctx, on_finish, journal_op_tid, features, false);
1348 req->send();
1349 }
1350}
1351
1352template <typename I>
1353int Operations<I>::metadata_set(const std::string &key,
1354 const std::string &value) {
1355 CephContext *cct = m_image_ctx.cct;
1356 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << ", value="
1357 << value << dendl;
1358
b32b8144
FG
1359 std::string config_key;
1360 bool config_override = util::is_metadata_config_override(key, &config_key);
1361 if (config_override) {
7c673cae 1362 // validate config setting
b32b8144 1363 int r = md_config_t().set_val(config_key.c_str(), value);
7c673cae
FG
1364 if (r < 0) {
1365 return r;
1366 }
1367 }
1368
1369 int r = m_image_ctx.state->refresh_if_required();
1370 if (r < 0) {
1371 return r;
1372 }
1373
1374 if (m_image_ctx.read_only) {
1375 return -EROFS;
1376 }
1377
b32b8144 1378 C_SaferCond metadata_ctx;
7c673cae
FG
1379 {
1380 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
b32b8144
FG
1381 r = prepare_image_update(true);
1382 if (r < 0) {
1383 return r;
7c673cae
FG
1384 }
1385
1386 execute_metadata_set(key, value, &metadata_ctx);
b32b8144
FG
1387 }
1388
1389 r = metadata_ctx.wait();
1390 if (config_override && r >= 0) {
1391 // apply new config key immediately
1392 r = m_image_ctx.state->refresh_if_required();
7c673cae
FG
1393 }
1394
1395 return r;
1396}
1397
1398template <typename I>
1399void Operations<I>::execute_metadata_set(const std::string &key,
1400 const std::string &value,
1401 Context *on_finish) {
1402 assert(m_image_ctx.owner_lock.is_locked());
1403
1404 CephContext *cct = m_image_ctx.cct;
1405 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << ", value="
1406 << value << dendl;
1407
1408 operation::MetadataSetRequest<I> *request =
b32b8144
FG
1409 new operation::MetadataSetRequest<I>(m_image_ctx,
1410 new C_NotifyUpdate<I>(m_image_ctx, on_finish),
1411 key, value);
7c673cae
FG
1412 request->send();
1413}
1414
1415template <typename I>
1416int Operations<I>::metadata_remove(const std::string &key) {
1417 CephContext *cct = m_image_ctx.cct;
1418 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
1419
1420 if (m_image_ctx.read_only) {
1421 return -EROFS;
1422 }
1423
1424 int r = m_image_ctx.state->refresh_if_required();
1425 if (r < 0) {
1426 return r;
1427 }
1428
1429 if (m_image_ctx.read_only) {
1430 return -EROFS;
1431 }
1432
d2e6a577
FG
1433 std::string value;
1434 r = cls_client::metadata_get(&m_image_ctx.md_ctx, m_image_ctx.header_oid, key, &value);
1435 if(r < 0)
1436 return r;
1437
b32b8144 1438 C_SaferCond metadata_ctx;
7c673cae
FG
1439 {
1440 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
b32b8144
FG
1441 r = prepare_image_update(true);
1442 if (r < 0) {
1443 return r;
7c673cae
FG
1444 }
1445
1446 execute_metadata_remove(key, &metadata_ctx);
b32b8144
FG
1447 }
1448
1449 r = metadata_ctx.wait();
1450
1451 std::string config_key;
1452 if (util::is_metadata_config_override(key, &config_key) && r >= 0) {
1453 // apply new config key immediately
1454 r = m_image_ctx.state->refresh_if_required();
7c673cae
FG
1455 }
1456
1457 return r;
1458}
1459
1460template <typename I>
1461void Operations<I>::execute_metadata_remove(const std::string &key,
1462 Context *on_finish) {
1463 assert(m_image_ctx.owner_lock.is_locked());
1464
1465 CephContext *cct = m_image_ctx.cct;
1466 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
1467
1468 operation::MetadataRemoveRequest<I> *request =
b32b8144
FG
1469 new operation::MetadataRemoveRequest<I>(
1470 m_image_ctx,
1471 new C_NotifyUpdate<I>(m_image_ctx, on_finish), key);
7c673cae
FG
1472 request->send();
1473}
1474
1475template <typename I>
b32b8144 1476int Operations<I>::prepare_image_update(bool request_lock) {
7c673cae
FG
1477 assert(m_image_ctx.owner_lock.is_locked() &&
1478 !m_image_ctx.owner_lock.is_wlocked());
b32b8144 1479 if (m_image_ctx.image_watcher == nullptr) {
7c673cae
FG
1480 return -EROFS;
1481 }
1482
1483 // need to upgrade to a write lock
7c673cae
FG
1484 C_SaferCond ctx;
1485 m_image_ctx.owner_lock.put_read();
b32b8144 1486 bool attempting_lock = false;
7c673cae
FG
1487 {
1488 RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
1489 if (m_image_ctx.exclusive_lock != nullptr &&
1490 (!m_image_ctx.exclusive_lock->is_lock_owner() ||
31f18b77 1491 !m_image_ctx.exclusive_lock->accept_requests())) {
b32b8144
FG
1492
1493 attempting_lock = true;
1494 m_image_ctx.exclusive_lock->block_requests(0);
1495
1496 if (request_lock) {
1497 m_image_ctx.exclusive_lock->acquire_lock(&ctx);
1498 } else {
1499 m_image_ctx.exclusive_lock->try_acquire_lock(&ctx);
1500 }
7c673cae
FG
1501 }
1502 }
1503
31f18b77 1504 int r = 0;
b32b8144 1505 if (attempting_lock) {
7c673cae
FG
1506 r = ctx.wait();
1507 }
b32b8144 1508
7c673cae 1509 m_image_ctx.owner_lock.get_read();
b32b8144
FG
1510 if (attempting_lock && m_image_ctx.exclusive_lock != nullptr) {
1511 m_image_ctx.exclusive_lock->unblock_requests();
1512 }
7c673cae 1513
b32b8144
FG
1514 if (r < 0) {
1515 return r;
1516 } else if (m_image_ctx.exclusive_lock != nullptr &&
1517 !m_image_ctx.exclusive_lock->is_lock_owner()) {
1518 return -EROFS;
1519 }
1520
1521 return 0;
7c673cae
FG
1522}
1523
1524template <typename I>
1525int Operations<I>::invoke_async_request(const std::string& request_type,
1526 bool permit_snapshot,
1527 const boost::function<void(Context*)>& local_request,
1528 const boost::function<void(Context*)>& remote_request) {
1529 C_SaferCond ctx;
1530 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx,
1531 request_type,
1532 permit_snapshot,
1533 local_request,
1534 remote_request,
1535 {}, &ctx);
1536 req->send();
1537 return ctx.wait();
1538}
1539
1540} // namespace librbd
1541
1542template class librbd::Operations<librbd::ImageCtx>;