]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | #include <errno.h> | |
4 | #include <boost/assign/list_of.hpp> | |
5 | #include <stddef.h> | |
6 | ||
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" | |
13 | ||
7c673cae FG |
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" | |
b32b8144 | 25 | #include "librbd/Types.h" |
7c673cae FG |
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" | |
31f18b77 | 31 | #include "librbd/io/AsyncOperation.h" |
7c673cae | 32 | #include "librbd/io/ImageRequestWQ.h" |
11fdf7f2 | 33 | #include "librbd/io/ObjectDispatcher.h" |
7c673cae FG |
34 | #include "librbd/journal/StandardPolicy.h" |
35 | ||
36 | #include "osdc/Striper.h" | |
37 | #include <boost/bind.hpp> | |
11fdf7f2 | 38 | #include <boost/algorithm/string/predicate.hpp> |
7c673cae FG |
39 | |
40 | #define dout_subsys ceph_subsys_rbd | |
41 | #undef dout_prefix | |
42 | #define dout_prefix *_dout << "librbd::ImageCtx: " | |
43 | ||
44 | using std::map; | |
45 | using std::pair; | |
46 | using std::set; | |
47 | using std::string; | |
48 | using std::vector; | |
49 | ||
50 | using ceph::bufferlist; | |
51 | using librados::snap_t; | |
52 | using librados::IoCtx; | |
53 | ||
54 | namespace librbd { | |
55 | ||
56 | namespace { | |
57 | ||
58 | class ThreadPoolSingleton : public ThreadPool { | |
59 | public: | |
60 | ContextWQ *op_work_queue; | |
61 | ||
62 | explicit ThreadPoolSingleton(CephContext *cct) | |
63 | : ThreadPool(cct, "librbd::thread_pool", "tp_librbd", 1, | |
64 | "rbd_op_threads"), | |
65 | op_work_queue(new ContextWQ("librbd::op_work_queue", | |
11fdf7f2 | 66 | cct->_conf.get_val<uint64_t>("rbd_op_thread_timeout"), |
7c673cae FG |
67 | this)) { |
68 | start(); | |
69 | } | |
70 | ~ThreadPoolSingleton() override { | |
71 | op_work_queue->drain(); | |
72 | delete op_work_queue; | |
73 | ||
74 | stop(); | |
75 | } | |
76 | }; | |
77 | ||
78 | class SafeTimerSingleton : public SafeTimer { | |
79 | public: | |
80 | Mutex lock; | |
81 | ||
82 | explicit SafeTimerSingleton(CephContext *cct) | |
83 | : SafeTimer(cct, lock, true), | |
84 | lock("librbd::Journal::SafeTimerSingleton::lock") { | |
85 | init(); | |
86 | } | |
87 | ~SafeTimerSingleton() { | |
88 | Mutex::Locker locker(lock); | |
89 | shutdown(); | |
90 | } | |
91 | }; | |
92 | ||
7c673cae FG |
93 | } // anonymous namespace |
94 | ||
95 | const string ImageCtx::METADATA_CONF_PREFIX = "conf_"; | |
96 | ||
97 | ImageCtx::ImageCtx(const string &image_name, const string &image_id, | |
98 | const char *snap, IoCtx& p, bool ro) | |
99 | : cct((CephContext*)p.cct()), | |
11fdf7f2 | 100 | config(cct->_conf), |
7c673cae FG |
101 | perfcounter(NULL), |
102 | snap_id(CEPH_NOSNAP), | |
103 | snap_exists(true), | |
104 | read_only(ro), | |
7c673cae FG |
105 | exclusive_locked(false), |
106 | name(image_name), | |
107 | image_watcher(NULL), | |
108 | journal(NULL), | |
109 | owner_lock(util::unique_lock_name("librbd::ImageCtx::owner_lock", this)), | |
110 | md_lock(util::unique_lock_name("librbd::ImageCtx::md_lock", this)), | |
7c673cae | 111 | snap_lock(util::unique_lock_name("librbd::ImageCtx::snap_lock", this)), |
11fdf7f2 | 112 | timestamp_lock(util::unique_lock_name("librbd::ImageCtx::timestamp_lock", this)), |
7c673cae FG |
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)), | |
118 | extra_read_flags(0), | |
11fdf7f2 | 119 | old_format(false), |
7c673cae FG |
120 | order(0), size(0), features(0), |
121 | format_string(NULL), | |
122 | id(image_id), parent(NULL), | |
123 | stripe_unit(0), stripe_count(0), flags(0), | |
7c673cae FG |
124 | readahead(), |
125 | total_bytes_read(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), | |
31f18b77 FG |
130 | asok_hook(nullptr), |
131 | trace_endpoint("librbd") | |
7c673cae FG |
132 | { |
133 | md_ctx.dup(p); | |
134 | data_ctx.dup(p); | |
135 | if (snap) | |
136 | snap_name = snap; | |
137 | ||
138 | memset(&header, 0, sizeof(header)); | |
139 | ||
140 | ThreadPool *thread_pool; | |
141 | get_thread_pool_instance(cct, &thread_pool, &op_work_queue); | |
224ce89b | 142 | io_work_queue = new io::ImageRequestWQ<>( |
181888fb | 143 | this, "librbd::io_work_queue", |
11fdf7f2 | 144 | cct->_conf.get_val<uint64_t>("rbd_op_thread_timeout"), |
7c673cae | 145 | thread_pool); |
11fdf7f2 | 146 | io_object_dispatcher = new io::ObjectDispatcher<>(this); |
7c673cae | 147 | |
11fdf7f2 | 148 | if (cct->_conf.get_val<bool>("rbd_auto_exclusive_lock_until_manual_request")) { |
7c673cae FG |
149 | exclusive_lock_policy = new exclusive_lock::AutomaticPolicy(this); |
150 | } else { | |
151 | exclusive_lock_policy = new exclusive_lock::StandardPolicy(this); | |
152 | } | |
153 | journal_policy = new journal::StandardPolicy<ImageCtx>(this); | |
154 | } | |
155 | ||
11fdf7f2 TL |
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; | |
160 | } | |
161 | ||
7c673cae | 162 | ImageCtx::~ImageCtx() { |
11fdf7f2 TL |
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); | |
7c673cae FG |
168 | |
169 | if (perfcounter) { | |
170 | perf_stop(); | |
171 | } | |
7c673cae FG |
172 | delete[] format_string; |
173 | ||
174 | md_ctx.aio_flush(); | |
175 | data_ctx.aio_flush(); | |
176 | io_work_queue->drain(); | |
177 | ||
11fdf7f2 TL |
178 | delete io_object_dispatcher; |
179 | ||
7c673cae FG |
180 | delete journal_policy; |
181 | delete exclusive_lock_policy; | |
182 | delete io_work_queue; | |
183 | delete operations; | |
184 | delete state; | |
185 | } | |
186 | ||
187 | void ImageCtx::init() { | |
11fdf7f2 TL |
188 | ceph_assert(!header_oid.empty()); |
189 | ceph_assert(old_format || !id.empty()); | |
7c673cae FG |
190 | |
191 | asok_hook = new LibrbdAdminSocketHook(this); | |
192 | ||
193 | string pname = string("librbd-") + id + string("-") + | |
194 | data_ctx.get_pool_name() + string("-") + name; | |
195 | if (!snap_name.empty()) { | |
196 | pname += "-"; | |
197 | pname += snap_name; | |
198 | } | |
199 | ||
31f18b77 | 200 | trace_endpoint.copy_name(pname); |
7c673cae FG |
201 | perf_start(pname); |
202 | ||
11fdf7f2 TL |
203 | ceph_assert(image_watcher == NULL); |
204 | image_watcher = new ImageWatcher<>(*this); | |
7c673cae FG |
205 | } |
206 | ||
207 | void ImageCtx::shutdown() { | |
208 | delete image_watcher; | |
209 | image_watcher = nullptr; | |
210 | ||
211 | delete asok_hook; | |
212 | asok_hook = nullptr; | |
213 | } | |
214 | ||
215 | void ImageCtx::init_layout() | |
216 | { | |
217 | if (stripe_unit == 0 || stripe_count == 0) { | |
218 | stripe_unit = 1ull << order; | |
219 | stripe_count = 1; | |
220 | } | |
221 | ||
222 | vector<uint64_t> alignments; | |
223 | alignments.push_back(stripe_count << order); // object set (in file striping terminology) | |
224 | alignments.push_back(stripe_unit * stripe_count); // stripe | |
225 | alignments.push_back(stripe_unit); // stripe unit | |
226 | readahead.set_alignments(alignments); | |
227 | ||
228 | layout = file_layout_t(); | |
229 | layout.stripe_unit = stripe_unit; | |
230 | layout.stripe_count = stripe_count; | |
231 | layout.object_size = 1ull << order; | |
232 | layout.pool_id = data_ctx.get_id(); // FIXME: pool id overflow? | |
233 | ||
234 | delete[] format_string; | |
235 | size_t len = object_prefix.length() + 16; | |
236 | format_string = new char[len]; | |
237 | if (old_format) { | |
238 | snprintf(format_string, len, "%s.%%012llx", object_prefix.c_str()); | |
239 | } else { | |
240 | snprintf(format_string, len, "%s.%%016llx", object_prefix.c_str()); | |
241 | } | |
242 | ||
243 | ldout(cct, 10) << "init_layout stripe_unit " << stripe_unit | |
244 | << " stripe_count " << stripe_count | |
245 | << " object_size " << layout.object_size | |
246 | << " prefix " << object_prefix | |
247 | << " format " << format_string | |
248 | << dendl; | |
249 | } | |
250 | ||
251 | void ImageCtx::perf_start(string name) { | |
b32b8144 FG |
252 | auto perf_prio = PerfCountersBuilder::PRIO_DEBUGONLY; |
253 | if (child == nullptr) { | |
254 | // ensure top-level IO stats are exported for librbd daemons | |
255 | perf_prio = PerfCountersBuilder::PRIO_USEFUL; | |
256 | } | |
257 | ||
7c673cae FG |
258 | PerfCountersBuilder plb(cct, name, l_librbd_first, l_librbd_last); |
259 | ||
b32b8144 FG |
260 | plb.add_u64_counter(l_librbd_rd, "rd", "Reads", "r", perf_prio); |
261 | plb.add_u64_counter(l_librbd_rd_bytes, "rd_bytes", "Data size in reads", | |
11fdf7f2 | 262 | "rb", perf_prio, unit_t(UNIT_BYTES)); |
b32b8144 FG |
263 | plb.add_time_avg(l_librbd_rd_latency, "rd_latency", "Latency of reads", |
264 | "rl", perf_prio); | |
265 | plb.add_u64_counter(l_librbd_wr, "wr", "Writes", "w", perf_prio); | |
266 | plb.add_u64_counter(l_librbd_wr_bytes, "wr_bytes", "Written data", | |
11fdf7f2 | 267 | "wb", perf_prio, unit_t(UNIT_BYTES)); |
b32b8144 FG |
268 | plb.add_time_avg(l_librbd_wr_latency, "wr_latency", "Write latency", |
269 | "wl", perf_prio); | |
7c673cae | 270 | plb.add_u64_counter(l_librbd_discard, "discard", "Discards"); |
11fdf7f2 | 271 | plb.add_u64_counter(l_librbd_discard_bytes, "discard_bytes", "Discarded data", NULL, 0, unit_t(UNIT_BYTES)); |
7c673cae FG |
272 | plb.add_time_avg(l_librbd_discard_latency, "discard_latency", "Discard latency"); |
273 | plb.add_u64_counter(l_librbd_flush, "flush", "Flushes"); | |
11fdf7f2 | 274 | plb.add_time_avg(l_librbd_flush_latency, "flush_latency", "Latency of flushes"); |
7c673cae | 275 | plb.add_u64_counter(l_librbd_ws, "ws", "WriteSames"); |
11fdf7f2 | 276 | plb.add_u64_counter(l_librbd_ws_bytes, "ws_bytes", "WriteSame data", NULL, 0, unit_t(UNIT_BYTES)); |
7c673cae | 277 | plb.add_time_avg(l_librbd_ws_latency, "ws_latency", "WriteSame latency"); |
c07f9fc5 | 278 | plb.add_u64_counter(l_librbd_cmp, "cmp", "CompareAndWrites"); |
11fdf7f2 | 279 | plb.add_u64_counter(l_librbd_cmp_bytes, "cmp_bytes", "Data size in cmps", NULL, 0, unit_t(UNIT_BYTES)); |
c07f9fc5 | 280 | plb.add_time_avg(l_librbd_cmp_latency, "cmp_latency", "Latency of cmps"); |
7c673cae FG |
281 | plb.add_u64_counter(l_librbd_snap_create, "snap_create", "Snap creations"); |
282 | plb.add_u64_counter(l_librbd_snap_remove, "snap_remove", "Snap removals"); | |
283 | plb.add_u64_counter(l_librbd_snap_rollback, "snap_rollback", "Snap rollbacks"); | |
284 | plb.add_u64_counter(l_librbd_snap_rename, "snap_rename", "Snap rename"); | |
285 | plb.add_u64_counter(l_librbd_notify, "notify", "Updated header notifications"); | |
286 | plb.add_u64_counter(l_librbd_resize, "resize", "Resizes"); | |
287 | plb.add_u64_counter(l_librbd_readahead, "readahead", "Read ahead"); | |
11fdf7f2 | 288 | plb.add_u64_counter(l_librbd_readahead_bytes, "readahead_bytes", "Data size in read ahead", NULL, 0, unit_t(UNIT_BYTES)); |
7c673cae FG |
289 | plb.add_u64_counter(l_librbd_invalidate_cache, "invalidate_cache", "Cache invalidates"); |
290 | ||
b32b8144 FG |
291 | plb.add_time(l_librbd_opened_time, "opened_time", "Opened time", |
292 | "ots", perf_prio); | |
293 | plb.add_time(l_librbd_lock_acquired_time, "lock_acquired_time", | |
294 | "Lock acquired time", "lats", perf_prio); | |
295 | ||
7c673cae FG |
296 | perfcounter = plb.create_perf_counters(); |
297 | cct->get_perfcounters_collection()->add(perfcounter); | |
b32b8144 FG |
298 | |
299 | perfcounter->tset(l_librbd_opened_time, ceph_clock_now()); | |
7c673cae FG |
300 | } |
301 | ||
302 | void ImageCtx::perf_stop() { | |
11fdf7f2 | 303 | ceph_assert(perfcounter); |
7c673cae FG |
304 | cct->get_perfcounters_collection()->remove(perfcounter); |
305 | delete perfcounter; | |
306 | } | |
307 | ||
308 | void ImageCtx::set_read_flag(unsigned flag) { | |
309 | extra_read_flags |= flag; | |
310 | } | |
311 | ||
312 | int ImageCtx::get_read_flags(snap_t snap_id) { | |
313 | int flags = librados::OPERATION_NOFLAG | extra_read_flags; | |
314 | if (snap_id == LIBRADOS_SNAP_HEAD) | |
315 | return flags; | |
316 | ||
11fdf7f2 | 317 | if (config.get_val<bool>("rbd_balance_snap_reads")) |
7c673cae | 318 | flags |= librados::OPERATION_BALANCE_READS; |
11fdf7f2 | 319 | else if (config.get_val<bool>("rbd_localize_snap_reads")) |
7c673cae FG |
320 | flags |= librados::OPERATION_LOCALIZE_READS; |
321 | return flags; | |
322 | } | |
323 | ||
11fdf7f2 TL |
324 | int ImageCtx::snap_set(uint64_t in_snap_id) { |
325 | ceph_assert(snap_lock.is_wlocked()); | |
326 | auto it = snap_info.find(in_snap_id); | |
327 | if (in_snap_id != CEPH_NOSNAP && it != snap_info.end()) { | |
7c673cae | 328 | snap_id = in_snap_id; |
11fdf7f2 TL |
329 | snap_namespace = it->second.snap_namespace; |
330 | snap_name = it->second.name; | |
7c673cae FG |
331 | snap_exists = true; |
332 | data_ctx.snap_set_read(snap_id); | |
333 | return 0; | |
334 | } | |
335 | return -ENOENT; | |
336 | } | |
337 | ||
338 | void ImageCtx::snap_unset() | |
339 | { | |
11fdf7f2 | 340 | ceph_assert(snap_lock.is_wlocked()); |
7c673cae FG |
341 | snap_id = CEPH_NOSNAP; |
342 | snap_namespace = {}; | |
343 | snap_name = ""; | |
344 | snap_exists = true; | |
345 | data_ctx.snap_set_read(snap_id); | |
346 | } | |
347 | ||
11fdf7f2 TL |
348 | snap_t ImageCtx::get_snap_id(const cls::rbd::SnapshotNamespace& in_snap_namespace, |
349 | const string& in_snap_name) const | |
7c673cae | 350 | { |
11fdf7f2 | 351 | ceph_assert(snap_lock.is_locked()); |
7c673cae | 352 | auto it = snap_ids.find({in_snap_namespace, in_snap_name}); |
11fdf7f2 | 353 | if (it != snap_ids.end()) { |
7c673cae | 354 | return it->second; |
11fdf7f2 | 355 | } |
7c673cae FG |
356 | return CEPH_NOSNAP; |
357 | } | |
358 | ||
359 | const SnapInfo* ImageCtx::get_snap_info(snap_t in_snap_id) const | |
360 | { | |
11fdf7f2 | 361 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
362 | map<snap_t, SnapInfo>::const_iterator it = |
363 | snap_info.find(in_snap_id); | |
364 | if (it != snap_info.end()) | |
365 | return &it->second; | |
11fdf7f2 | 366 | return nullptr; |
7c673cae FG |
367 | } |
368 | ||
369 | int ImageCtx::get_snap_name(snap_t in_snap_id, | |
370 | string *out_snap_name) const | |
371 | { | |
11fdf7f2 | 372 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
373 | const SnapInfo *info = get_snap_info(in_snap_id); |
374 | if (info) { | |
375 | *out_snap_name = info->name; | |
376 | return 0; | |
377 | } | |
378 | return -ENOENT; | |
379 | } | |
380 | ||
381 | int ImageCtx::get_snap_namespace(snap_t in_snap_id, | |
382 | cls::rbd::SnapshotNamespace *out_snap_namespace) const | |
383 | { | |
11fdf7f2 | 384 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
385 | const SnapInfo *info = get_snap_info(in_snap_id); |
386 | if (info) { | |
387 | *out_snap_namespace = info->snap_namespace; | |
388 | return 0; | |
389 | } | |
390 | return -ENOENT; | |
391 | } | |
392 | ||
393 | int ImageCtx::get_parent_spec(snap_t in_snap_id, | |
11fdf7f2 | 394 | cls::rbd::ParentImageSpec *out_pspec) const |
7c673cae FG |
395 | { |
396 | const SnapInfo *info = get_snap_info(in_snap_id); | |
397 | if (info) { | |
398 | *out_pspec = info->parent.spec; | |
399 | return 0; | |
400 | } | |
401 | return -ENOENT; | |
402 | } | |
403 | ||
404 | uint64_t ImageCtx::get_current_size() const | |
405 | { | |
11fdf7f2 | 406 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
407 | return size; |
408 | } | |
409 | ||
410 | uint64_t ImageCtx::get_object_size() const | |
411 | { | |
412 | return 1ull << order; | |
413 | } | |
414 | ||
415 | string ImageCtx::get_object_name(uint64_t num) const { | |
416 | char buf[object_prefix.length() + 32]; | |
417 | snprintf(buf, sizeof(buf), format_string, num); | |
418 | return string(buf); | |
419 | } | |
420 | ||
421 | uint64_t ImageCtx::get_stripe_unit() const | |
422 | { | |
423 | return stripe_unit; | |
424 | } | |
425 | ||
426 | uint64_t ImageCtx::get_stripe_count() const | |
427 | { | |
428 | return stripe_count; | |
429 | } | |
430 | ||
431 | uint64_t ImageCtx::get_stripe_period() const | |
432 | { | |
433 | return stripe_count * (1ull << order); | |
434 | } | |
435 | ||
31f18b77 FG |
436 | utime_t ImageCtx::get_create_timestamp() const |
437 | { | |
438 | return create_timestamp; | |
439 | } | |
440 | ||
11fdf7f2 TL |
441 | utime_t ImageCtx::get_access_timestamp() const |
442 | { | |
443 | return access_timestamp; | |
444 | } | |
445 | ||
446 | utime_t ImageCtx::get_modify_timestamp() const | |
447 | { | |
448 | return modify_timestamp; | |
449 | } | |
450 | ||
451 | void ImageCtx::set_access_timestamp(utime_t at) | |
452 | { | |
453 | ceph_assert(timestamp_lock.is_wlocked()); | |
454 | access_timestamp = at; | |
455 | } | |
456 | ||
457 | void ImageCtx::set_modify_timestamp(utime_t mt) | |
458 | { | |
459 | ceph_assert(timestamp_lock.is_locked()); | |
460 | modify_timestamp = mt; | |
461 | } | |
462 | ||
7c673cae FG |
463 | int ImageCtx::is_snap_protected(snap_t in_snap_id, |
464 | bool *is_protected) const | |
465 | { | |
11fdf7f2 | 466 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
467 | const SnapInfo *info = get_snap_info(in_snap_id); |
468 | if (info) { | |
469 | *is_protected = | |
470 | (info->protection_status == RBD_PROTECTION_STATUS_PROTECTED); | |
471 | return 0; | |
472 | } | |
473 | return -ENOENT; | |
474 | } | |
475 | ||
476 | int ImageCtx::is_snap_unprotected(snap_t in_snap_id, | |
477 | bool *is_unprotected) const | |
478 | { | |
11fdf7f2 | 479 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
480 | const SnapInfo *info = get_snap_info(in_snap_id); |
481 | if (info) { | |
482 | *is_unprotected = | |
483 | (info->protection_status == RBD_PROTECTION_STATUS_UNPROTECTED); | |
484 | return 0; | |
485 | } | |
486 | return -ENOENT; | |
487 | } | |
488 | ||
489 | void ImageCtx::add_snap(cls::rbd::SnapshotNamespace in_snap_namespace, | |
490 | string in_snap_name, | |
491 | snap_t id, uint64_t in_size, | |
11fdf7f2 TL |
492 | const ParentImageInfo &parent, |
493 | uint8_t protection_status, uint64_t flags, | |
494 | utime_t timestamp) | |
7c673cae | 495 | { |
11fdf7f2 | 496 | ceph_assert(snap_lock.is_wlocked()); |
7c673cae FG |
497 | snaps.push_back(id); |
498 | SnapInfo info(in_snap_name, in_snap_namespace, | |
499 | in_size, parent, protection_status, flags, timestamp); | |
500 | snap_info.insert({id, info}); | |
501 | snap_ids.insert({{in_snap_namespace, in_snap_name}, id}); | |
502 | } | |
503 | ||
504 | void ImageCtx::rm_snap(cls::rbd::SnapshotNamespace in_snap_namespace, | |
505 | string in_snap_name, | |
506 | snap_t id) | |
507 | { | |
11fdf7f2 | 508 | ceph_assert(snap_lock.is_wlocked()); |
7c673cae FG |
509 | snaps.erase(std::remove(snaps.begin(), snaps.end(), id), snaps.end()); |
510 | snap_info.erase(id); | |
511 | snap_ids.erase({in_snap_namespace, in_snap_name}); | |
512 | } | |
513 | ||
514 | uint64_t ImageCtx::get_image_size(snap_t in_snap_id) const | |
515 | { | |
11fdf7f2 | 516 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
517 | if (in_snap_id == CEPH_NOSNAP) { |
518 | if (!resize_reqs.empty() && | |
519 | resize_reqs.front()->shrinking()) { | |
520 | return resize_reqs.front()->get_image_size(); | |
521 | } | |
522 | return size; | |
523 | } | |
524 | ||
525 | const SnapInfo *info = get_snap_info(in_snap_id); | |
526 | if (info) { | |
527 | return info->size; | |
528 | } | |
529 | return 0; | |
530 | } | |
531 | ||
532 | uint64_t ImageCtx::get_object_count(snap_t in_snap_id) const { | |
11fdf7f2 | 533 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
534 | uint64_t image_size = get_image_size(in_snap_id); |
535 | return Striper::get_num_objects(layout, image_size); | |
536 | } | |
537 | ||
538 | bool ImageCtx::test_features(uint64_t features) const | |
539 | { | |
540 | RWLock::RLocker l(snap_lock); | |
541 | return test_features(features, snap_lock); | |
542 | } | |
543 | ||
544 | bool ImageCtx::test_features(uint64_t in_features, | |
545 | const RWLock &in_snap_lock) const | |
546 | { | |
11fdf7f2 | 547 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
548 | return ((features & in_features) == in_features); |
549 | } | |
550 | ||
11fdf7f2 TL |
551 | bool ImageCtx::test_op_features(uint64_t in_op_features) const |
552 | { | |
553 | RWLock::RLocker snap_locker(snap_lock); | |
554 | return test_op_features(in_op_features, snap_lock); | |
555 | } | |
556 | ||
557 | bool ImageCtx::test_op_features(uint64_t in_op_features, | |
558 | const RWLock &in_snap_lock) const | |
559 | { | |
560 | ceph_assert(snap_lock.is_locked()); | |
561 | return ((op_features & in_op_features) == in_op_features); | |
562 | } | |
563 | ||
7c673cae FG |
564 | int ImageCtx::get_flags(librados::snap_t _snap_id, uint64_t *_flags) const |
565 | { | |
11fdf7f2 | 566 | ceph_assert(snap_lock.is_locked()); |
7c673cae FG |
567 | if (_snap_id == CEPH_NOSNAP) { |
568 | *_flags = flags; | |
569 | return 0; | |
570 | } | |
571 | const SnapInfo *info = get_snap_info(_snap_id); | |
572 | if (info) { | |
573 | *_flags = info->flags; | |
574 | return 0; | |
575 | } | |
576 | return -ENOENT; | |
577 | } | |
578 | ||
91327a77 AA |
579 | int ImageCtx::test_flags(librados::snap_t in_snap_id, |
580 | uint64_t flags, bool *flags_set) const | |
7c673cae FG |
581 | { |
582 | RWLock::RLocker l(snap_lock); | |
91327a77 | 583 | return test_flags(in_snap_id, flags, snap_lock, flags_set); |
7c673cae FG |
584 | } |
585 | ||
91327a77 AA |
586 | int ImageCtx::test_flags(librados::snap_t in_snap_id, |
587 | uint64_t flags, const RWLock &in_snap_lock, | |
31f18b77 | 588 | bool *flags_set) const |
7c673cae | 589 | { |
11fdf7f2 | 590 | ceph_assert(snap_lock.is_locked()); |
7c673cae | 591 | uint64_t snap_flags; |
91327a77 | 592 | int r = get_flags(in_snap_id, &snap_flags); |
31f18b77 FG |
593 | if (r < 0) { |
594 | return r; | |
595 | } | |
596 | *flags_set = ((snap_flags & flags) == flags); | |
597 | return 0; | |
7c673cae FG |
598 | } |
599 | ||
600 | int ImageCtx::update_flags(snap_t in_snap_id, uint64_t flag, bool enabled) | |
601 | { | |
11fdf7f2 | 602 | ceph_assert(snap_lock.is_wlocked()); |
7c673cae FG |
603 | uint64_t *_flags; |
604 | if (in_snap_id == CEPH_NOSNAP) { | |
605 | _flags = &flags; | |
606 | } else { | |
607 | map<snap_t, SnapInfo>::iterator it = snap_info.find(in_snap_id); | |
608 | if (it == snap_info.end()) { | |
609 | return -ENOENT; | |
610 | } | |
611 | _flags = &it->second.flags; | |
612 | } | |
613 | ||
614 | if (enabled) { | |
615 | (*_flags) |= flag; | |
616 | } else { | |
617 | (*_flags) &= ~flag; | |
618 | } | |
619 | return 0; | |
620 | } | |
621 | ||
11fdf7f2 | 622 | const ParentImageInfo* ImageCtx::get_parent_info(snap_t in_snap_id) const |
7c673cae | 623 | { |
11fdf7f2 TL |
624 | ceph_assert(snap_lock.is_locked()); |
625 | ceph_assert(parent_lock.is_locked()); | |
7c673cae FG |
626 | if (in_snap_id == CEPH_NOSNAP) |
627 | return &parent_md; | |
628 | const SnapInfo *info = get_snap_info(in_snap_id); | |
629 | if (info) | |
630 | return &info->parent; | |
631 | return NULL; | |
632 | } | |
633 | ||
634 | int64_t ImageCtx::get_parent_pool_id(snap_t in_snap_id) const | |
635 | { | |
11fdf7f2 | 636 | const auto info = get_parent_info(in_snap_id); |
7c673cae FG |
637 | if (info) |
638 | return info->spec.pool_id; | |
639 | return -1; | |
640 | } | |
641 | ||
642 | string ImageCtx::get_parent_image_id(snap_t in_snap_id) const | |
643 | { | |
11fdf7f2 | 644 | const auto info = get_parent_info(in_snap_id); |
7c673cae FG |
645 | if (info) |
646 | return info->spec.image_id; | |
647 | return ""; | |
648 | } | |
649 | ||
650 | uint64_t ImageCtx::get_parent_snap_id(snap_t in_snap_id) const | |
651 | { | |
11fdf7f2 | 652 | const auto info = get_parent_info(in_snap_id); |
7c673cae FG |
653 | if (info) |
654 | return info->spec.snap_id; | |
655 | return CEPH_NOSNAP; | |
656 | } | |
657 | ||
658 | int ImageCtx::get_parent_overlap(snap_t in_snap_id, uint64_t *overlap) const | |
659 | { | |
11fdf7f2 TL |
660 | ceph_assert(snap_lock.is_locked()); |
661 | const auto info = get_parent_info(in_snap_id); | |
7c673cae FG |
662 | if (info) { |
663 | *overlap = info->overlap; | |
664 | return 0; | |
665 | } | |
666 | return -ENOENT; | |
667 | } | |
668 | ||
7c673cae | 669 | void ImageCtx::register_watch(Context *on_finish) { |
11fdf7f2 | 670 | ceph_assert(image_watcher != NULL); |
7c673cae FG |
671 | image_watcher->register_watch(on_finish); |
672 | } | |
673 | ||
674 | uint64_t ImageCtx::prune_parent_extents(vector<pair<uint64_t,uint64_t> >& objectx, | |
675 | uint64_t overlap) | |
676 | { | |
677 | // drop extents completely beyond the overlap | |
678 | while (!objectx.empty() && objectx.back().first >= overlap) | |
679 | objectx.pop_back(); | |
680 | ||
681 | // trim final overlapping extent | |
682 | if (!objectx.empty() && objectx.back().first + objectx.back().second > overlap) | |
683 | objectx.back().second = overlap - objectx.back().first; | |
684 | ||
685 | uint64_t len = 0; | |
686 | for (vector<pair<uint64_t,uint64_t> >::iterator p = objectx.begin(); | |
687 | p != objectx.end(); | |
688 | ++p) | |
689 | len += p->second; | |
690 | ldout(cct, 10) << "prune_parent_extents image overlap " << overlap | |
691 | << ", object overlap " << len | |
692 | << " from image extents " << objectx << dendl; | |
693 | return len; | |
694 | } | |
695 | ||
7c673cae FG |
696 | void ImageCtx::cancel_async_requests() { |
697 | C_SaferCond ctx; | |
698 | cancel_async_requests(&ctx); | |
699 | ctx.wait(); | |
700 | } | |
701 | ||
702 | void ImageCtx::cancel_async_requests(Context *on_finish) { | |
703 | { | |
704 | Mutex::Locker async_ops_locker(async_ops_lock); | |
705 | if (!async_requests.empty()) { | |
706 | ldout(cct, 10) << "canceling async requests: count=" | |
707 | << async_requests.size() << dendl; | |
708 | for (auto req : async_requests) { | |
709 | ldout(cct, 10) << "canceling async request: " << req << dendl; | |
710 | req->cancel(); | |
711 | } | |
712 | async_requests_waiters.push_back(on_finish); | |
713 | return; | |
714 | } | |
715 | } | |
716 | ||
717 | on_finish->complete(0); | |
718 | } | |
719 | ||
720 | void ImageCtx::clear_pending_completions() { | |
721 | Mutex::Locker l(completed_reqs_lock); | |
722 | ldout(cct, 10) << "clear pending AioCompletion: count=" | |
723 | << completed_reqs.size() << dendl; | |
724 | completed_reqs.clear(); | |
725 | } | |
726 | ||
11fdf7f2 TL |
727 | void ImageCtx::apply_metadata(const std::map<std::string, bufferlist> &meta, |
728 | bool thread_safe) { | |
729 | ldout(cct, 20) << __func__ << dendl; | |
7c673cae | 730 | |
11fdf7f2 TL |
731 | // reset settings back to global defaults |
732 | for (auto& key : config_overrides) { | |
733 | std::string value; | |
734 | int r = cct->_conf.get_val(key, &value); | |
735 | ceph_assert(r == 0); | |
736 | ||
737 | config.set_val(key, value); | |
738 | } | |
739 | config_overrides.clear(); | |
7c673cae | 740 | |
11fdf7f2 TL |
741 | // extract config overrides |
742 | for (auto meta_pair : meta) { | |
743 | if (!boost::starts_with(meta_pair.first, METADATA_CONF_PREFIX)) { | |
7c673cae | 744 | continue; |
11fdf7f2 | 745 | } |
7c673cae | 746 | |
11fdf7f2 TL |
747 | std::string key = meta_pair.first.substr(METADATA_CONF_PREFIX.size()); |
748 | if (!boost::starts_with(key, "rbd_")) { | |
749 | // ignore non-RBD configuration keys | |
750 | // TODO use option schema to determine applicable subsystem | |
751 | ldout(cct, 0) << __func__ << ": ignoring config " << key << dendl; | |
752 | continue; | |
7c673cae | 753 | } |
7c673cae | 754 | |
11fdf7f2 TL |
755 | if (config.find_option(key) != nullptr) { |
756 | std::string val(meta_pair.second.c_str(), meta_pair.second.length()); | |
757 | int r = config.set_val(key, val); | |
758 | if (r >= 0) { | |
759 | ldout(cct, 20) << __func__ << ": " << key << "=" << val << dendl; | |
760 | config_overrides.insert(key); | |
761 | } else { | |
762 | lderr(cct) << __func__ << ": failed to set config " << key << " " | |
763 | << "with value " << val << ": " << cpp_strerror(r) | |
764 | << dendl; | |
765 | } | |
7c673cae FG |
766 | } |
767 | } | |
768 | ||
11fdf7f2 TL |
769 | #define ASSIGN_OPTION(param, type) \ |
770 | param = config.get_val<type>("rbd_"#param) | |
7c673cae | 771 | |
11fdf7f2 | 772 | bool skip_partial_discard = true; |
181888fb FG |
773 | ASSIGN_OPTION(non_blocking_aio, bool); |
774 | ASSIGN_OPTION(cache, bool); | |
775 | ASSIGN_OPTION(cache_writethrough_until_flush, bool); | |
11fdf7f2 TL |
776 | ASSIGN_OPTION(cache_max_dirty, Option::size_t); |
777 | ASSIGN_OPTION(sparse_read_threshold_bytes, Option::size_t); | |
778 | ASSIGN_OPTION(readahead_max_bytes, Option::size_t); | |
779 | ASSIGN_OPTION(readahead_disable_after_bytes, Option::size_t); | |
181888fb | 780 | ASSIGN_OPTION(clone_copy_on_read, bool); |
181888fb | 781 | ASSIGN_OPTION(enable_alloc_hint, bool); |
11fdf7f2 TL |
782 | ASSIGN_OPTION(mirroring_replay_delay, uint64_t); |
783 | ASSIGN_OPTION(mtime_update_interval, uint64_t); | |
784 | ASSIGN_OPTION(atime_update_interval, uint64_t); | |
181888fb | 785 | ASSIGN_OPTION(skip_partial_discard, bool); |
11fdf7f2 | 786 | ASSIGN_OPTION(discard_granularity_bytes, uint64_t); |
181888fb | 787 | ASSIGN_OPTION(blkin_trace_all, bool); |
b32b8144 | 788 | |
11fdf7f2 | 789 | #undef ASSIGN_OPTION |
b32b8144 FG |
790 | |
791 | if (sparse_read_threshold_bytes == 0) { | |
792 | sparse_read_threshold_bytes = get_object_size(); | |
793 | } | |
11fdf7f2 TL |
794 | if (!skip_partial_discard) { |
795 | discard_granularity_bytes = 0; | |
796 | } | |
797 | ||
798 | io_work_queue->apply_qos_schedule_tick_min( | |
799 | config.get_val<uint64_t>("rbd_qos_schedule_tick_min")); | |
800 | ||
801 | io_work_queue->apply_qos_limit( | |
802 | RBD_QOS_IOPS_THROTTLE, | |
803 | config.get_val<uint64_t>("rbd_qos_iops_limit"), | |
804 | config.get_val<uint64_t>("rbd_qos_iops_burst")); | |
805 | io_work_queue->apply_qos_limit( | |
806 | RBD_QOS_BPS_THROTTLE, | |
807 | config.get_val<uint64_t>("rbd_qos_bps_limit"), | |
808 | config.get_val<uint64_t>("rbd_qos_bps_burst")); | |
809 | io_work_queue->apply_qos_limit( | |
810 | RBD_QOS_READ_IOPS_THROTTLE, | |
811 | config.get_val<uint64_t>("rbd_qos_read_iops_limit"), | |
812 | config.get_val<uint64_t>("rbd_qos_read_iops_burst")); | |
813 | io_work_queue->apply_qos_limit( | |
814 | RBD_QOS_WRITE_IOPS_THROTTLE, | |
815 | config.get_val<uint64_t>("rbd_qos_write_iops_limit"), | |
816 | config.get_val<uint64_t>("rbd_qos_write_iops_burst")); | |
817 | io_work_queue->apply_qos_limit( | |
818 | RBD_QOS_READ_BPS_THROTTLE, | |
819 | config.get_val<uint64_t>("rbd_qos_read_bps_limit"), | |
820 | config.get_val<uint64_t>("rbd_qos_read_bps_burst")); | |
821 | io_work_queue->apply_qos_limit( | |
822 | RBD_QOS_WRITE_BPS_THROTTLE, | |
823 | config.get_val<uint64_t>("rbd_qos_write_bps_limit"), | |
824 | config.get_val<uint64_t>("rbd_qos_write_bps_burst")); | |
7c673cae FG |
825 | } |
826 | ||
827 | ExclusiveLock<ImageCtx> *ImageCtx::create_exclusive_lock() { | |
828 | return new ExclusiveLock<ImageCtx>(*this); | |
829 | } | |
830 | ||
831 | ObjectMap<ImageCtx> *ImageCtx::create_object_map(uint64_t snap_id) { | |
832 | return new ObjectMap<ImageCtx>(*this, snap_id); | |
833 | } | |
834 | ||
835 | Journal<ImageCtx> *ImageCtx::create_journal() { | |
836 | return new Journal<ImageCtx>(*this); | |
837 | } | |
838 | ||
839 | void ImageCtx::set_image_name(const std::string &image_name) { | |
840 | // update the name so rename can be invoked repeatedly | |
841 | RWLock::RLocker owner_locker(owner_lock); | |
842 | RWLock::WLocker snap_locker(snap_lock); | |
843 | name = image_name; | |
844 | if (old_format) { | |
845 | header_oid = util::old_header_name(image_name); | |
846 | } | |
847 | } | |
848 | ||
849 | void ImageCtx::notify_update() { | |
850 | state->handle_update_notification(); | |
851 | ImageWatcher<>::notify_header_update(md_ctx, header_oid); | |
852 | } | |
853 | ||
854 | void ImageCtx::notify_update(Context *on_finish) { | |
855 | state->handle_update_notification(); | |
856 | image_watcher->notify_header_update(on_finish); | |
857 | } | |
858 | ||
859 | exclusive_lock::Policy *ImageCtx::get_exclusive_lock_policy() const { | |
11fdf7f2 TL |
860 | ceph_assert(owner_lock.is_locked()); |
861 | ceph_assert(exclusive_lock_policy != nullptr); | |
7c673cae FG |
862 | return exclusive_lock_policy; |
863 | } | |
864 | ||
865 | void ImageCtx::set_exclusive_lock_policy(exclusive_lock::Policy *policy) { | |
11fdf7f2 TL |
866 | ceph_assert(owner_lock.is_wlocked()); |
867 | ceph_assert(policy != nullptr); | |
7c673cae FG |
868 | delete exclusive_lock_policy; |
869 | exclusive_lock_policy = policy; | |
870 | } | |
871 | ||
872 | journal::Policy *ImageCtx::get_journal_policy() const { | |
11fdf7f2 TL |
873 | ceph_assert(snap_lock.is_locked()); |
874 | ceph_assert(journal_policy != nullptr); | |
7c673cae FG |
875 | return journal_policy; |
876 | } | |
877 | ||
878 | void ImageCtx::set_journal_policy(journal::Policy *policy) { | |
11fdf7f2 TL |
879 | ceph_assert(snap_lock.is_wlocked()); |
880 | ceph_assert(policy != nullptr); | |
7c673cae FG |
881 | delete journal_policy; |
882 | journal_policy = policy; | |
883 | } | |
884 | ||
28e407b8 AA |
885 | bool ImageCtx::is_writeback_cache_enabled() const { |
886 | return (cache && cache_max_dirty > 0); | |
887 | } | |
888 | ||
7c673cae FG |
889 | void ImageCtx::get_thread_pool_instance(CephContext *cct, |
890 | ThreadPool **thread_pool, | |
891 | ContextWQ **op_work_queue) { | |
11fdf7f2 TL |
892 | auto thread_pool_singleton = |
893 | &cct->lookup_or_create_singleton_object<ThreadPoolSingleton>( | |
894 | "librbd::thread_pool", false, cct); | |
7c673cae FG |
895 | *thread_pool = thread_pool_singleton; |
896 | *op_work_queue = thread_pool_singleton->op_work_queue; | |
897 | } | |
898 | ||
899 | void ImageCtx::get_timer_instance(CephContext *cct, SafeTimer **timer, | |
900 | Mutex **timer_lock) { | |
11fdf7f2 TL |
901 | auto safe_timer_singleton = |
902 | &cct->lookup_or_create_singleton_object<SafeTimerSingleton>( | |
903 | "librbd::journal::safe_timer", false, cct); | |
7c673cae FG |
904 | *timer = safe_timer_singleton; |
905 | *timer_lock = &safe_timer_singleton->lock; | |
906 | } | |
907 | } |