1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include <boost/assign/list_of.hpp>
7 #include "common/ceph_context.h"
8 #include "common/dout.h"
9 #include "common/errno.h"
10 #include "common/perf_counters.h"
11 #include "common/WorkQueue.h"
12 #include "common/Timer.h"
14 #include "librbd/AsyncRequest.h"
15 #include "librbd/ExclusiveLock.h"
16 #include "librbd/internal.h"
17 #include "librbd/ImageCtx.h"
18 #include "librbd/ImageState.h"
19 #include "librbd/ImageWatcher.h"
20 #include "librbd/Journal.h"
21 #include "librbd/LibrbdAdminSocketHook.h"
22 #include "librbd/ObjectMap.h"
23 #include "librbd/Operations.h"
24 #include "librbd/operation/ResizeRequest.h"
25 #include "librbd/Types.h"
26 #include "librbd/Utils.h"
27 #include "librbd/LibrbdWriteback.h"
28 #include "librbd/exclusive_lock/AutomaticPolicy.h"
29 #include "librbd/exclusive_lock/StandardPolicy.h"
30 #include "librbd/io/AioCompletion.h"
31 #include "librbd/io/AsyncOperation.h"
32 #include "librbd/io/ImageRequestWQ.h"
33 #include "librbd/io/ObjectDispatcher.h"
34 #include "librbd/journal/StandardPolicy.h"
36 #include "osdc/Striper.h"
37 #include <boost/bind.hpp>
38 #include <boost/algorithm/string/predicate.hpp>
40 #define dout_subsys ceph_subsys_rbd
42 #define dout_prefix *_dout << "librbd::ImageCtx: "
50 using ceph::bufferlist
;
51 using librados::snap_t
;
52 using librados::IoCtx
;
58 class ThreadPoolSingleton
: public ThreadPool
{
60 ContextWQ
*op_work_queue
;
62 explicit ThreadPoolSingleton(CephContext
*cct
)
63 : ThreadPool(cct
, "librbd::thread_pool", "tp_librbd", 1,
65 op_work_queue(new ContextWQ("librbd::op_work_queue",
66 cct
->_conf
.get_val
<uint64_t>("rbd_op_thread_timeout"),
70 ~ThreadPoolSingleton() override
{
71 op_work_queue
->drain();
78 class SafeTimerSingleton
: public SafeTimer
{
82 explicit SafeTimerSingleton(CephContext
*cct
)
83 : SafeTimer(cct
, lock
, true),
84 lock("librbd::Journal::SafeTimerSingleton::lock") {
87 ~SafeTimerSingleton() {
88 Mutex::Locker
locker(lock
);
93 } // anonymous namespace
95 const string
ImageCtx::METADATA_CONF_PREFIX
= "conf_";
97 ImageCtx::ImageCtx(const string
&image_name
, const string
&image_id
,
98 const char *snap
, IoCtx
& p
, bool ro
)
99 : cct((CephContext
*)p
.cct()),
102 snap_id(CEPH_NOSNAP
),
105 exclusive_locked(false),
109 owner_lock(util::unique_lock_name("librbd::ImageCtx::owner_lock", this)),
110 md_lock(util::unique_lock_name("librbd::ImageCtx::md_lock", this)),
111 snap_lock(util::unique_lock_name("librbd::ImageCtx::snap_lock", this)),
112 timestamp_lock(util::unique_lock_name("librbd::ImageCtx::timestamp_lock", this)),
113 parent_lock(util::unique_lock_name("librbd::ImageCtx::parent_lock", this)),
114 object_map_lock(util::unique_lock_name("librbd::ImageCtx::object_map_lock", this)),
115 async_ops_lock(util::unique_lock_name("librbd::ImageCtx::async_ops_lock", this)),
116 copyup_list_lock(util::unique_lock_name("librbd::ImageCtx::copyup_list_lock", this)),
117 completed_reqs_lock(util::unique_lock_name("librbd::ImageCtx::completed_reqs_lock", this)),
120 order(0), size(0), features(0),
122 id(image_id
), parent(NULL
),
123 stripe_unit(0), stripe_count(0), flags(0),
126 state(new ImageState
<>(this)),
127 operations(new Operations
<>(*this)),
128 exclusive_lock(nullptr), object_map(nullptr),
129 io_work_queue(nullptr), op_work_queue(nullptr),
131 trace_endpoint("librbd")
138 memset(&header
, 0, sizeof(header
));
140 ThreadPool
*thread_pool
;
141 get_thread_pool_instance(cct
, &thread_pool
, &op_work_queue
);
142 io_work_queue
= new io::ImageRequestWQ
<>(
143 this, "librbd::io_work_queue",
144 cct
->_conf
.get_val
<uint64_t>("rbd_op_thread_timeout"),
146 io_object_dispatcher
= new io::ObjectDispatcher
<>(this);
148 if (cct
->_conf
.get_val
<bool>("rbd_auto_exclusive_lock_until_manual_request")) {
149 exclusive_lock_policy
= new exclusive_lock::AutomaticPolicy(this);
151 exclusive_lock_policy
= new exclusive_lock::StandardPolicy(this);
153 journal_policy
= new journal::StandardPolicy
<ImageCtx
>(this);
156 ImageCtx::ImageCtx(const string
&image_name
, const string
&image_id
,
157 uint64_t snap_id
, IoCtx
& p
, bool ro
)
158 : ImageCtx(image_name
, image_id
, "", p
, ro
) {
159 open_snap_id
= snap_id
;
162 ImageCtx::~ImageCtx() {
163 ceph_assert(image_watcher
== NULL
);
164 ceph_assert(exclusive_lock
== NULL
);
165 ceph_assert(object_map
== NULL
);
166 ceph_assert(journal
== NULL
);
167 ceph_assert(asok_hook
== NULL
);
172 delete[] format_string
;
175 if (data_ctx
.is_valid()) {
176 data_ctx
.aio_flush();
178 io_work_queue
->drain();
180 delete io_object_dispatcher
;
182 delete journal_policy
;
183 delete exclusive_lock_policy
;
184 delete io_work_queue
;
189 void ImageCtx::init() {
190 ceph_assert(!header_oid
.empty());
191 ceph_assert(old_format
|| !id
.empty());
193 asok_hook
= new LibrbdAdminSocketHook(this);
195 string pname
= string("librbd-") + id
+ string("-") +
196 md_ctx
.get_pool_name() + string("-") + name
;
197 if (!snap_name
.empty()) {
202 trace_endpoint
.copy_name(pname
);
205 ceph_assert(image_watcher
== NULL
);
206 image_watcher
= new ImageWatcher
<>(*this);
209 void ImageCtx::shutdown() {
210 delete image_watcher
;
211 image_watcher
= nullptr;
217 void ImageCtx::init_layout(int64_t pool_id
)
219 if (stripe_unit
== 0 || stripe_count
== 0) {
220 stripe_unit
= 1ull << order
;
224 vector
<uint64_t> alignments
;
225 alignments
.push_back(stripe_count
<< order
); // object set (in file striping terminology)
226 alignments
.push_back(stripe_unit
* stripe_count
); // stripe
227 alignments
.push_back(stripe_unit
); // stripe unit
228 readahead
.set_alignments(alignments
);
230 layout
= file_layout_t();
231 layout
.stripe_unit
= stripe_unit
;
232 layout
.stripe_count
= stripe_count
;
233 layout
.object_size
= 1ull << order
;
234 layout
.pool_id
= pool_id
; // FIXME: pool id overflow?
236 delete[] format_string
;
237 size_t len
= object_prefix
.length() + 16;
238 format_string
= new char[len
];
240 snprintf(format_string
, len
, "%s.%%012llx", object_prefix
.c_str());
242 snprintf(format_string
, len
, "%s.%%016llx", object_prefix
.c_str());
245 ldout(cct
, 10) << "init_layout stripe_unit " << stripe_unit
246 << " stripe_count " << stripe_count
247 << " object_size " << layout
.object_size
248 << " prefix " << object_prefix
249 << " format " << format_string
253 void ImageCtx::perf_start(string name
) {
254 auto perf_prio
= PerfCountersBuilder::PRIO_DEBUGONLY
;
255 if (child
== nullptr) {
256 // ensure top-level IO stats are exported for librbd daemons
257 perf_prio
= PerfCountersBuilder::PRIO_USEFUL
;
260 PerfCountersBuilder
plb(cct
, name
, l_librbd_first
, l_librbd_last
);
262 plb
.add_u64_counter(l_librbd_rd
, "rd", "Reads", "r", perf_prio
);
263 plb
.add_u64_counter(l_librbd_rd_bytes
, "rd_bytes", "Data size in reads",
264 "rb", perf_prio
, unit_t(UNIT_BYTES
));
265 plb
.add_time_avg(l_librbd_rd_latency
, "rd_latency", "Latency of reads",
267 plb
.add_u64_counter(l_librbd_wr
, "wr", "Writes", "w", perf_prio
);
268 plb
.add_u64_counter(l_librbd_wr_bytes
, "wr_bytes", "Written data",
269 "wb", perf_prio
, unit_t(UNIT_BYTES
));
270 plb
.add_time_avg(l_librbd_wr_latency
, "wr_latency", "Write latency",
272 plb
.add_u64_counter(l_librbd_discard
, "discard", "Discards");
273 plb
.add_u64_counter(l_librbd_discard_bytes
, "discard_bytes", "Discarded data", NULL
, 0, unit_t(UNIT_BYTES
));
274 plb
.add_time_avg(l_librbd_discard_latency
, "discard_latency", "Discard latency");
275 plb
.add_u64_counter(l_librbd_flush
, "flush", "Flushes");
276 plb
.add_time_avg(l_librbd_flush_latency
, "flush_latency", "Latency of flushes");
277 plb
.add_u64_counter(l_librbd_ws
, "ws", "WriteSames");
278 plb
.add_u64_counter(l_librbd_ws_bytes
, "ws_bytes", "WriteSame data", NULL
, 0, unit_t(UNIT_BYTES
));
279 plb
.add_time_avg(l_librbd_ws_latency
, "ws_latency", "WriteSame latency");
280 plb
.add_u64_counter(l_librbd_cmp
, "cmp", "CompareAndWrites");
281 plb
.add_u64_counter(l_librbd_cmp_bytes
, "cmp_bytes", "Data size in cmps", NULL
, 0, unit_t(UNIT_BYTES
));
282 plb
.add_time_avg(l_librbd_cmp_latency
, "cmp_latency", "Latency of cmps");
283 plb
.add_u64_counter(l_librbd_snap_create
, "snap_create", "Snap creations");
284 plb
.add_u64_counter(l_librbd_snap_remove
, "snap_remove", "Snap removals");
285 plb
.add_u64_counter(l_librbd_snap_rollback
, "snap_rollback", "Snap rollbacks");
286 plb
.add_u64_counter(l_librbd_snap_rename
, "snap_rename", "Snap rename");
287 plb
.add_u64_counter(l_librbd_notify
, "notify", "Updated header notifications");
288 plb
.add_u64_counter(l_librbd_resize
, "resize", "Resizes");
289 plb
.add_u64_counter(l_librbd_readahead
, "readahead", "Read ahead");
290 plb
.add_u64_counter(l_librbd_readahead_bytes
, "readahead_bytes", "Data size in read ahead", NULL
, 0, unit_t(UNIT_BYTES
));
291 plb
.add_u64_counter(l_librbd_invalidate_cache
, "invalidate_cache", "Cache invalidates");
293 plb
.add_time(l_librbd_opened_time
, "opened_time", "Opened time",
295 plb
.add_time(l_librbd_lock_acquired_time
, "lock_acquired_time",
296 "Lock acquired time", "lats", perf_prio
);
298 perfcounter
= plb
.create_perf_counters();
299 cct
->get_perfcounters_collection()->add(perfcounter
);
301 perfcounter
->tset(l_librbd_opened_time
, ceph_clock_now());
304 void ImageCtx::perf_stop() {
305 ceph_assert(perfcounter
);
306 cct
->get_perfcounters_collection()->remove(perfcounter
);
310 void ImageCtx::set_read_flag(unsigned flag
) {
311 extra_read_flags
|= flag
;
314 int ImageCtx::get_read_flags(snap_t snap_id
) {
315 int flags
= librados::OPERATION_NOFLAG
| extra_read_flags
;
316 if (snap_id
== LIBRADOS_SNAP_HEAD
)
319 if (config
.get_val
<bool>("rbd_balance_snap_reads"))
320 flags
|= librados::OPERATION_BALANCE_READS
;
321 else if (config
.get_val
<bool>("rbd_localize_snap_reads"))
322 flags
|= librados::OPERATION_LOCALIZE_READS
;
326 int ImageCtx::snap_set(uint64_t in_snap_id
) {
327 ceph_assert(snap_lock
.is_wlocked());
328 auto it
= snap_info
.find(in_snap_id
);
329 if (in_snap_id
!= CEPH_NOSNAP
&& it
!= snap_info
.end()) {
330 snap_id
= in_snap_id
;
331 snap_namespace
= it
->second
.snap_namespace
;
332 snap_name
= it
->second
.name
;
334 if (data_ctx
.is_valid()) {
335 data_ctx
.snap_set_read(snap_id
);
342 void ImageCtx::snap_unset()
344 ceph_assert(snap_lock
.is_wlocked());
345 snap_id
= CEPH_NOSNAP
;
349 if (data_ctx
.is_valid()) {
350 data_ctx
.snap_set_read(snap_id
);
354 snap_t
ImageCtx::get_snap_id(const cls::rbd::SnapshotNamespace
& in_snap_namespace
,
355 const string
& in_snap_name
) const
357 ceph_assert(snap_lock
.is_locked());
358 auto it
= snap_ids
.find({in_snap_namespace
, in_snap_name
});
359 if (it
!= snap_ids
.end()) {
365 const SnapInfo
* ImageCtx::get_snap_info(snap_t in_snap_id
) const
367 ceph_assert(snap_lock
.is_locked());
368 map
<snap_t
, SnapInfo
>::const_iterator it
=
369 snap_info
.find(in_snap_id
);
370 if (it
!= snap_info
.end())
375 int ImageCtx::get_snap_name(snap_t in_snap_id
,
376 string
*out_snap_name
) const
378 ceph_assert(snap_lock
.is_locked());
379 const SnapInfo
*info
= get_snap_info(in_snap_id
);
381 *out_snap_name
= info
->name
;
387 int ImageCtx::get_snap_namespace(snap_t in_snap_id
,
388 cls::rbd::SnapshotNamespace
*out_snap_namespace
) const
390 ceph_assert(snap_lock
.is_locked());
391 const SnapInfo
*info
= get_snap_info(in_snap_id
);
393 *out_snap_namespace
= info
->snap_namespace
;
399 int ImageCtx::get_parent_spec(snap_t in_snap_id
,
400 cls::rbd::ParentImageSpec
*out_pspec
) const
402 const SnapInfo
*info
= get_snap_info(in_snap_id
);
404 *out_pspec
= info
->parent
.spec
;
410 uint64_t ImageCtx::get_current_size() const
412 ceph_assert(snap_lock
.is_locked());
416 uint64_t ImageCtx::get_object_size() const
418 return 1ull << order
;
421 string
ImageCtx::get_object_name(uint64_t num
) const {
422 char buf
[object_prefix
.length() + 32];
423 snprintf(buf
, sizeof(buf
), format_string
, num
);
427 uint64_t ImageCtx::get_stripe_unit() const
432 uint64_t ImageCtx::get_stripe_count() const
437 uint64_t ImageCtx::get_stripe_period() const
439 return stripe_count
* (1ull << order
);
442 utime_t
ImageCtx::get_create_timestamp() const
444 return create_timestamp
;
447 utime_t
ImageCtx::get_access_timestamp() const
449 return access_timestamp
;
452 utime_t
ImageCtx::get_modify_timestamp() const
454 return modify_timestamp
;
457 void ImageCtx::set_access_timestamp(utime_t at
)
459 ceph_assert(timestamp_lock
.is_wlocked());
460 access_timestamp
= at
;
463 void ImageCtx::set_modify_timestamp(utime_t mt
)
465 ceph_assert(timestamp_lock
.is_locked());
466 modify_timestamp
= mt
;
469 int ImageCtx::is_snap_protected(snap_t in_snap_id
,
470 bool *is_protected
) const
472 ceph_assert(snap_lock
.is_locked());
473 const SnapInfo
*info
= get_snap_info(in_snap_id
);
476 (info
->protection_status
== RBD_PROTECTION_STATUS_PROTECTED
);
482 int ImageCtx::is_snap_unprotected(snap_t in_snap_id
,
483 bool *is_unprotected
) const
485 ceph_assert(snap_lock
.is_locked());
486 const SnapInfo
*info
= get_snap_info(in_snap_id
);
489 (info
->protection_status
== RBD_PROTECTION_STATUS_UNPROTECTED
);
495 void ImageCtx::add_snap(cls::rbd::SnapshotNamespace in_snap_namespace
,
497 snap_t id
, uint64_t in_size
,
498 const ParentImageInfo
&parent
,
499 uint8_t protection_status
, uint64_t flags
,
502 ceph_assert(snap_lock
.is_wlocked());
504 SnapInfo
info(in_snap_name
, in_snap_namespace
,
505 in_size
, parent
, protection_status
, flags
, timestamp
);
506 snap_info
.insert({id
, info
});
507 snap_ids
.insert({{in_snap_namespace
, in_snap_name
}, id
});
510 void ImageCtx::rm_snap(cls::rbd::SnapshotNamespace in_snap_namespace
,
514 ceph_assert(snap_lock
.is_wlocked());
515 snaps
.erase(std::remove(snaps
.begin(), snaps
.end(), id
), snaps
.end());
517 snap_ids
.erase({in_snap_namespace
, in_snap_name
});
520 uint64_t ImageCtx::get_image_size(snap_t in_snap_id
) const
522 ceph_assert(snap_lock
.is_locked());
523 if (in_snap_id
== CEPH_NOSNAP
) {
524 if (!resize_reqs
.empty() &&
525 resize_reqs
.front()->shrinking()) {
526 return resize_reqs
.front()->get_image_size();
531 const SnapInfo
*info
= get_snap_info(in_snap_id
);
538 uint64_t ImageCtx::get_object_count(snap_t in_snap_id
) const {
539 ceph_assert(snap_lock
.is_locked());
540 uint64_t image_size
= get_image_size(in_snap_id
);
541 return Striper::get_num_objects(layout
, image_size
);
544 bool ImageCtx::test_features(uint64_t features
) const
546 RWLock::RLocker
l(snap_lock
);
547 return test_features(features
, snap_lock
);
550 bool ImageCtx::test_features(uint64_t in_features
,
551 const RWLock
&in_snap_lock
) const
553 ceph_assert(snap_lock
.is_locked());
554 return ((features
& in_features
) == in_features
);
557 bool ImageCtx::test_op_features(uint64_t in_op_features
) const
559 RWLock::RLocker
snap_locker(snap_lock
);
560 return test_op_features(in_op_features
, snap_lock
);
563 bool ImageCtx::test_op_features(uint64_t in_op_features
,
564 const RWLock
&in_snap_lock
) const
566 ceph_assert(snap_lock
.is_locked());
567 return ((op_features
& in_op_features
) == in_op_features
);
570 int ImageCtx::get_flags(librados::snap_t _snap_id
, uint64_t *_flags
) const
572 ceph_assert(snap_lock
.is_locked());
573 if (_snap_id
== CEPH_NOSNAP
) {
577 const SnapInfo
*info
= get_snap_info(_snap_id
);
579 *_flags
= info
->flags
;
585 int ImageCtx::test_flags(librados::snap_t in_snap_id
,
586 uint64_t flags
, bool *flags_set
) const
588 RWLock::RLocker
l(snap_lock
);
589 return test_flags(in_snap_id
, flags
, snap_lock
, flags_set
);
592 int ImageCtx::test_flags(librados::snap_t in_snap_id
,
593 uint64_t flags
, const RWLock
&in_snap_lock
,
594 bool *flags_set
) const
596 ceph_assert(snap_lock
.is_locked());
598 int r
= get_flags(in_snap_id
, &snap_flags
);
602 *flags_set
= ((snap_flags
& flags
) == flags
);
606 int ImageCtx::update_flags(snap_t in_snap_id
, uint64_t flag
, bool enabled
)
608 ceph_assert(snap_lock
.is_wlocked());
610 if (in_snap_id
== CEPH_NOSNAP
) {
613 map
<snap_t
, SnapInfo
>::iterator it
= snap_info
.find(in_snap_id
);
614 if (it
== snap_info
.end()) {
617 _flags
= &it
->second
.flags
;
628 const ParentImageInfo
* ImageCtx::get_parent_info(snap_t in_snap_id
) const
630 ceph_assert(snap_lock
.is_locked());
631 ceph_assert(parent_lock
.is_locked());
632 if (in_snap_id
== CEPH_NOSNAP
)
634 const SnapInfo
*info
= get_snap_info(in_snap_id
);
636 return &info
->parent
;
640 int64_t ImageCtx::get_parent_pool_id(snap_t in_snap_id
) const
642 const auto info
= get_parent_info(in_snap_id
);
644 return info
->spec
.pool_id
;
648 string
ImageCtx::get_parent_image_id(snap_t in_snap_id
) const
650 const auto info
= get_parent_info(in_snap_id
);
652 return info
->spec
.image_id
;
656 uint64_t ImageCtx::get_parent_snap_id(snap_t in_snap_id
) const
658 const auto info
= get_parent_info(in_snap_id
);
660 return info
->spec
.snap_id
;
664 int ImageCtx::get_parent_overlap(snap_t in_snap_id
, uint64_t *overlap
) const
666 ceph_assert(snap_lock
.is_locked());
667 const auto info
= get_parent_info(in_snap_id
);
669 *overlap
= info
->overlap
;
675 void ImageCtx::register_watch(Context
*on_finish
) {
676 ceph_assert(image_watcher
!= NULL
);
677 image_watcher
->register_watch(on_finish
);
680 uint64_t ImageCtx::prune_parent_extents(vector
<pair
<uint64_t,uint64_t> >& objectx
,
683 // drop extents completely beyond the overlap
684 while (!objectx
.empty() && objectx
.back().first
>= overlap
)
687 // trim final overlapping extent
688 if (!objectx
.empty() && objectx
.back().first
+ objectx
.back().second
> overlap
)
689 objectx
.back().second
= overlap
- objectx
.back().first
;
692 for (vector
<pair
<uint64_t,uint64_t> >::iterator p
= objectx
.begin();
696 ldout(cct
, 10) << "prune_parent_extents image overlap " << overlap
697 << ", object overlap " << len
698 << " from image extents " << objectx
<< dendl
;
702 void ImageCtx::cancel_async_requests() {
704 cancel_async_requests(&ctx
);
708 void ImageCtx::cancel_async_requests(Context
*on_finish
) {
710 Mutex::Locker
async_ops_locker(async_ops_lock
);
711 if (!async_requests
.empty()) {
712 ldout(cct
, 10) << "canceling async requests: count="
713 << async_requests
.size() << dendl
;
714 for (auto req
: async_requests
) {
715 ldout(cct
, 10) << "canceling async request: " << req
<< dendl
;
718 async_requests_waiters
.push_back(on_finish
);
723 on_finish
->complete(0);
726 void ImageCtx::clear_pending_completions() {
727 Mutex::Locker
l(completed_reqs_lock
);
728 ldout(cct
, 10) << "clear pending AioCompletion: count="
729 << completed_reqs
.size() << dendl
;
730 completed_reqs
.clear();
733 void ImageCtx::apply_metadata(const std::map
<std::string
, bufferlist
> &meta
,
735 ldout(cct
, 20) << __func__
<< dendl
;
737 // reset settings back to global defaults
738 for (auto& key
: config_overrides
) {
740 int r
= cct
->_conf
.get_val(key
, &value
);
743 config
.set_val(key
, value
);
745 config_overrides
.clear();
747 // extract config overrides
748 for (auto meta_pair
: meta
) {
749 if (!boost::starts_with(meta_pair
.first
, METADATA_CONF_PREFIX
)) {
753 std::string key
= meta_pair
.first
.substr(METADATA_CONF_PREFIX
.size());
754 if (!boost::starts_with(key
, "rbd_")) {
755 // ignore non-RBD configuration keys
756 // TODO use option schema to determine applicable subsystem
757 ldout(cct
, 0) << __func__
<< ": ignoring config " << key
<< dendl
;
761 if (config
.find_option(key
) != nullptr) {
762 std::string
val(meta_pair
.second
.c_str(), meta_pair
.second
.length());
763 int r
= config
.set_val(key
, val
);
765 ldout(cct
, 20) << __func__
<< ": " << key
<< "=" << val
<< dendl
;
766 config_overrides
.insert(key
);
768 lderr(cct
) << __func__
<< ": failed to set config " << key
<< " "
769 << "with value " << val
<< ": " << cpp_strerror(r
)
775 #define ASSIGN_OPTION(param, type) \
776 param = config.get_val<type>("rbd_"#param)
778 bool skip_partial_discard
= true;
779 ASSIGN_OPTION(non_blocking_aio
, bool);
780 ASSIGN_OPTION(cache
, bool);
781 ASSIGN_OPTION(cache_writethrough_until_flush
, bool);
782 ASSIGN_OPTION(cache_max_dirty
, Option::size_t);
783 ASSIGN_OPTION(sparse_read_threshold_bytes
, Option::size_t);
784 ASSIGN_OPTION(readahead_max_bytes
, Option::size_t);
785 ASSIGN_OPTION(readahead_disable_after_bytes
, Option::size_t);
786 ASSIGN_OPTION(clone_copy_on_read
, bool);
787 ASSIGN_OPTION(enable_alloc_hint
, bool);
788 ASSIGN_OPTION(mirroring_replay_delay
, uint64_t);
789 ASSIGN_OPTION(mtime_update_interval
, uint64_t);
790 ASSIGN_OPTION(atime_update_interval
, uint64_t);
791 ASSIGN_OPTION(skip_partial_discard
, bool);
792 ASSIGN_OPTION(discard_granularity_bytes
, uint64_t);
793 ASSIGN_OPTION(blkin_trace_all
, bool);
797 if (sparse_read_threshold_bytes
== 0) {
798 sparse_read_threshold_bytes
= get_object_size();
800 if (!skip_partial_discard
) {
801 discard_granularity_bytes
= 0;
804 io_work_queue
->apply_qos_schedule_tick_min(
805 config
.get_val
<uint64_t>("rbd_qos_schedule_tick_min"));
807 io_work_queue
->apply_qos_limit(
808 RBD_QOS_IOPS_THROTTLE
,
809 config
.get_val
<uint64_t>("rbd_qos_iops_limit"),
810 config
.get_val
<uint64_t>("rbd_qos_iops_burst"));
811 io_work_queue
->apply_qos_limit(
812 RBD_QOS_BPS_THROTTLE
,
813 config
.get_val
<uint64_t>("rbd_qos_bps_limit"),
814 config
.get_val
<uint64_t>("rbd_qos_bps_burst"));
815 io_work_queue
->apply_qos_limit(
816 RBD_QOS_READ_IOPS_THROTTLE
,
817 config
.get_val
<uint64_t>("rbd_qos_read_iops_limit"),
818 config
.get_val
<uint64_t>("rbd_qos_read_iops_burst"));
819 io_work_queue
->apply_qos_limit(
820 RBD_QOS_WRITE_IOPS_THROTTLE
,
821 config
.get_val
<uint64_t>("rbd_qos_write_iops_limit"),
822 config
.get_val
<uint64_t>("rbd_qos_write_iops_burst"));
823 io_work_queue
->apply_qos_limit(
824 RBD_QOS_READ_BPS_THROTTLE
,
825 config
.get_val
<uint64_t>("rbd_qos_read_bps_limit"),
826 config
.get_val
<uint64_t>("rbd_qos_read_bps_burst"));
827 io_work_queue
->apply_qos_limit(
828 RBD_QOS_WRITE_BPS_THROTTLE
,
829 config
.get_val
<uint64_t>("rbd_qos_write_bps_limit"),
830 config
.get_val
<uint64_t>("rbd_qos_write_bps_burst"));
833 ExclusiveLock
<ImageCtx
> *ImageCtx::create_exclusive_lock() {
834 return new ExclusiveLock
<ImageCtx
>(*this);
837 ObjectMap
<ImageCtx
> *ImageCtx::create_object_map(uint64_t snap_id
) {
838 return new ObjectMap
<ImageCtx
>(*this, snap_id
);
841 Journal
<ImageCtx
> *ImageCtx::create_journal() {
842 return new Journal
<ImageCtx
>(*this);
845 void ImageCtx::set_image_name(const std::string
&image_name
) {
846 // update the name so rename can be invoked repeatedly
847 RWLock::RLocker
owner_locker(owner_lock
);
848 RWLock::WLocker
snap_locker(snap_lock
);
851 header_oid
= util::old_header_name(image_name
);
855 void ImageCtx::notify_update() {
856 state
->handle_update_notification();
857 ImageWatcher
<>::notify_header_update(md_ctx
, header_oid
);
860 void ImageCtx::notify_update(Context
*on_finish
) {
861 state
->handle_update_notification();
862 image_watcher
->notify_header_update(on_finish
);
865 exclusive_lock::Policy
*ImageCtx::get_exclusive_lock_policy() const {
866 ceph_assert(owner_lock
.is_locked());
867 ceph_assert(exclusive_lock_policy
!= nullptr);
868 return exclusive_lock_policy
;
871 void ImageCtx::set_exclusive_lock_policy(exclusive_lock::Policy
*policy
) {
872 ceph_assert(owner_lock
.is_wlocked());
873 ceph_assert(policy
!= nullptr);
874 delete exclusive_lock_policy
;
875 exclusive_lock_policy
= policy
;
878 journal::Policy
*ImageCtx::get_journal_policy() const {
879 ceph_assert(snap_lock
.is_locked());
880 ceph_assert(journal_policy
!= nullptr);
881 return journal_policy
;
884 void ImageCtx::set_journal_policy(journal::Policy
*policy
) {
885 ceph_assert(snap_lock
.is_wlocked());
886 ceph_assert(policy
!= nullptr);
887 delete journal_policy
;
888 journal_policy
= policy
;
891 bool ImageCtx::is_writeback_cache_enabled() const {
892 return (cache
&& cache_max_dirty
> 0);
895 void ImageCtx::get_thread_pool_instance(CephContext
*cct
,
896 ThreadPool
**thread_pool
,
897 ContextWQ
**op_work_queue
) {
898 auto thread_pool_singleton
=
899 &cct
->lookup_or_create_singleton_object
<ThreadPoolSingleton
>(
900 "librbd::thread_pool", false, cct
);
901 *thread_pool
= thread_pool_singleton
;
902 *op_work_queue
= thread_pool_singleton
->op_work_queue
;
905 void ImageCtx::get_timer_instance(CephContext
*cct
, SafeTimer
**timer
,
906 Mutex
**timer_lock
) {
907 auto safe_timer_singleton
=
908 &cct
->lookup_or_create_singleton_object
<SafeTimerSingleton
>(
909 "librbd::journal::safe_timer", false, cct
);
910 *timer
= safe_timer_singleton
;
911 *timer_lock
= &safe_timer_singleton
->lock
;