]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/cache/pwl/ImageCacheState.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / librbd / cache / pwl / ImageCacheState.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "librbd/cache/Types.h"
5 #include "librbd/cache/Utils.h"
6 #include "librbd/cache/pwl/ImageCacheState.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/Operations.h"
9 #include "common/config_proxy.h"
10 #include "common/environment.h"
11 #include "common/hostname.h"
12 #include "librbd/plugin/Api.h"
13
14 #undef dout_subsys
15 #define dout_subsys ceph_subsys_rbd_pwl
16 #undef dout_prefix
17 #define dout_prefix *_dout << "librbd::cache::pwl::ImageCacheState: " \
18 << __func__ << ": "
19
20 namespace librbd {
21 namespace cache {
22 namespace pwl {
23
24 using namespace std;
25
26 template <typename I>
27 void ImageCacheState<I>::init_from_config() {
28 ldout(m_image_ctx->cct, 20) << dendl;
29
30 present = false;
31 empty = true;
32 clean = true;
33 host = "";
34 path = "";
35 ConfigProxy &config = m_image_ctx->config;
36 mode = config.get_val<std::string>("rbd_persistent_cache_mode");
37 size = 0;
38 }
39
40 template <typename I>
41 bool ImageCacheState<I>::init_from_metadata(json_spirit::mValue& json_root) {
42 ldout(m_image_ctx->cct, 20) << dendl;
43
44 try {
45 auto& o = json_root.get_obj();
46 present = o["present"].get_bool();
47 empty = o["empty"].get_bool();
48 clean = o["clean"].get_bool();
49 host = o["host"].get_str();
50 path = o["path"].get_str();
51 mode = o["mode"].get_str();
52 size = o["size"].get_uint64();
53 } catch (std::runtime_error& e) {
54 lderr(m_image_ctx->cct) << "failed to parse cache state: " << e.what()
55 << dendl;
56 return false;
57 }
58
59 return true;
60 }
61
62 template <typename I>
63 void ImageCacheState<I>::write_image_cache_state(std::unique_lock<ceph::mutex>& locker,
64 Context *on_finish) {
65 ceph_assert(ceph_mutex_is_locked_by_me(*locker.mutex()));
66 stats_timestamp = ceph_clock_now();
67 json_spirit::mObject o;
68 o["present"] = present;
69 o["empty"] = empty;
70 o["clean"] = clean;
71 o["host"] = host;
72 o["path"] = path;
73 o["mode"] = mode;
74 o["size"] = size;
75 o["stats_timestamp"] = stats_timestamp.sec();
76 o["allocated_bytes"] = allocated_bytes;
77 o["cached_bytes"] = cached_bytes;
78 o["dirty_bytes"] = dirty_bytes;
79 o["free_bytes"] = free_bytes;
80 o["hits_full"] = hits_full;
81 o["hits_partial"] = hits_partial;
82 o["misses"] = misses;
83 o["hit_bytes"] = hit_bytes;
84 o["miss_bytes"] = miss_bytes;
85 std::string image_state_json = json_spirit::write(o);
86 locker.unlock();
87
88 std::shared_lock owner_lock{m_image_ctx->owner_lock};
89 ldout(m_image_ctx->cct, 20) << __func__ << " Store state: "
90 << image_state_json << dendl;
91 m_plugin_api.execute_image_metadata_set(m_image_ctx, PERSISTENT_CACHE_STATE,
92 image_state_json, on_finish);
93 }
94
95 template <typename I>
96 void ImageCacheState<I>::clear_image_cache_state(Context *on_finish) {
97 std::shared_lock owner_lock{m_image_ctx->owner_lock};
98 ldout(m_image_ctx->cct, 20) << __func__ << " Remove state: " << dendl;
99 m_plugin_api.execute_image_metadata_remove(
100 m_image_ctx, PERSISTENT_CACHE_STATE, on_finish);
101 }
102
103 template <typename I>
104 ImageCacheState<I>* ImageCacheState<I>::create_image_cache_state(
105 I* image_ctx, plugin::Api<I>& plugin_api, int &r) {
106 std::string cache_state_str;
107 ImageCacheState<I>* cache_state = nullptr;
108
109 r = 0;
110 bool dirty_cache = plugin_api.test_image_features(image_ctx, RBD_FEATURE_DIRTY_CACHE);
111 if (dirty_cache) {
112 cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid,
113 PERSISTENT_CACHE_STATE, &cache_state_str);
114 }
115
116 ldout(image_ctx->cct, 20) << "image_cache_state: " << cache_state_str << dendl;
117
118 bool pwl_enabled = cache::util::is_pwl_enabled(*image_ctx);
119 bool cache_desired = pwl_enabled;
120 cache_desired &= !image_ctx->read_only;
121 cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_MIGRATING);
122 cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_JOURNALING);
123 cache_desired &= !image_ctx->old_format;
124
125 if (!dirty_cache && !cache_desired) {
126 ldout(image_ctx->cct, 20) << "Do not desire to use image cache." << dendl;
127 } else if (dirty_cache && !cache_desired) {
128 lderr(image_ctx->cct) << "There's a dirty cache, but RWL cache is disabled."
129 << dendl;
130 r = -EINVAL;
131 }else if ((!dirty_cache || cache_state_str.empty()) && cache_desired) {
132 cache_state = new ImageCacheState<I>(image_ctx, plugin_api);
133 cache_state->init_from_config();
134 } else {
135 ceph_assert(!cache_state_str.empty());
136 json_spirit::mValue json_root;
137 if (!json_spirit::read(cache_state_str.c_str(), json_root)) {
138 lderr(image_ctx->cct) << "failed to parse cache state" << dendl;
139 r = -EINVAL;
140 return nullptr;
141 }
142 cache_state = new ImageCacheState<I>(image_ctx, plugin_api);
143 if (!cache_state->init_from_metadata(json_root)) {
144 delete cache_state;
145 r = -EINVAL;
146 return nullptr;
147 }
148 if (!cache_state->present) {
149 cache_state->init_from_config();
150 }
151 }
152 return cache_state;
153 }
154
155 template <typename I>
156 ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state(
157 I* image_ctx, plugin::Api<I>& plugin_api) {
158 ImageCacheState<I>* cache_state = nullptr;
159 string cache_state_str;
160 cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid,
161 PERSISTENT_CACHE_STATE, &cache_state_str);
162 if (!cache_state_str.empty()) {
163 // ignore errors, best effort
164 cache_state = new ImageCacheState<I>(image_ctx, plugin_api);
165 json_spirit::mValue json_root;
166 if (!json_spirit::read(cache_state_str.c_str(), json_root)) {
167 lderr(image_ctx->cct) << "failed to parse cache state" << dendl;
168 } else {
169 cache_state->init_from_metadata(json_root);
170 }
171 }
172 return cache_state;
173 }
174
175 template <typename I>
176 bool ImageCacheState<I>::is_valid() {
177 if (this->present &&
178 (host.compare(ceph_get_short_hostname()) != 0)) {
179 auto cleanstring = "dirty";
180 if (this->clean) {
181 cleanstring = "clean";
182 }
183 lderr(m_image_ctx->cct) << "An image cache (RWL) remains on another host "
184 << host << " which is " << cleanstring
185 << ". Flush/close the image there to remove the "
186 << "image cache" << dendl;
187 return false;
188 }
189 return true;
190 }
191
192 } // namespace pwl
193 } // namespace cache
194 } // namespace librbd
195
196 template class librbd::cache::pwl::ImageCacheState<librbd::ImageCtx>;