void ImageCtx::init() {
assert(!header_oid.empty());
assert(old_format || !id.empty());
- if (!old_format) {
- init_layout();
- }
- apply_metadata_confs();
asok_hook = new LibrbdAdminSocketHook(this);
completed_reqs.clear();
}
- bool ImageCtx::_filter_metadata_confs(const string &prefix, map<string, bool> &configs,
- map<string, bufferlist> &pairs, map<string, bufferlist> *res) {
+ bool ImageCtx::_filter_metadata_confs(const string &prefix,
+ map<string, bool> &configs,
+ const map<string, bufferlist> &pairs,
+ map<string, bufferlist> *res) {
size_t conf_prefix_len = prefix.size();
string start = prefix;
- for (map<string, bufferlist>::iterator it = pairs.begin(); it != pairs.end(); ++it) {
- if (it->first.compare(0, MIN(conf_prefix_len, it->first.size()), prefix) > 0)
+ for (auto it : pairs) {
+ if (it.first.compare(0, MIN(conf_prefix_len, it.first.size()), prefix) > 0)
return false;
- if (it->first.size() <= conf_prefix_len)
+ if (it.first.size() <= conf_prefix_len)
continue;
- string key = it->first.substr(conf_prefix_len, it->first.size() - conf_prefix_len);
- map<string, bool>::iterator cit = configs.find(key);
- if ( cit != configs.end()) {
+ string key = it.first.substr(conf_prefix_len, it.first.size() - conf_prefix_len);
+ auto cit = configs.find(key);
+ if (cit != configs.end()) {
cit->second = true;
- res->insert(make_pair(key, it->second));
+ res->insert(make_pair(key, it.second));
}
}
return true;
}
- void ImageCtx::apply_metadata_confs() {
+ void ImageCtx::apply_metadata(const std::map<std::string, bufferlist> &meta) {
ldout(cct, 20) << __func__ << dendl;
- static uint64_t max_conf_items = 128;
std::map<string, bool> configs = boost::assign::map_list_of(
"rbd_non_blocking_aio", false)(
"rbd_cache", false)(
"rbd_journal_object_flush_age", false)(
"rbd_journal_pool", false);
- string start = METADATA_CONF_PREFIX;
md_config_t local_config_t;
-
- bool retrieve_metadata = !old_format;
- while (retrieve_metadata) {
- map<string, bufferlist> pairs, res;
- int r = cls_client::metadata_list(&md_ctx, header_oid, start, max_conf_items,
- &pairs);
- if (r == -EOPNOTSUPP || r == -EIO) {
- ldout(cct, 10) << "config metadata not supported by OSD" << dendl;
- break;
- } else if (r < 0) {
- lderr(cct) << __func__ << " couldn't list config metadata: " << r
+ std::map<std::string, bufferlist> res;
+
+ _filter_metadata_confs(METADATA_CONF_PREFIX, configs, meta, &res);
+ for (auto it : res) {
+ std::string val(it.second.c_str(), it.second.length());
+ int j = local_config_t.set_val(it.first.c_str(), val);
+ if (j < 0) {
+ lderr(cct) << __func__ << " failed to set config " << it.first
+ << " with value " << it.second.c_str() << ": " << j
<< dendl;
- break;
- }
- if (pairs.empty()) {
- break;
- }
-
- retrieve_metadata = _filter_metadata_confs(METADATA_CONF_PREFIX, configs,
- pairs, &res);
- for (map<string, bufferlist>::iterator it = res.begin();
- it != res.end(); ++it) {
- string val(it->second.c_str(), it->second.length());
- int j = local_config_t.set_val(it->first.c_str(), val);
- if (j < 0) {
- lderr(cct) << __func__ << " failed to set config " << it->first
- << " with value " << it->second.c_str() << ": " << j
- << dendl;
- }
}
- start = pairs.rbegin()->first;
}
#define ASSIGN_OPTION(config) \
journal::Policy *journal_policy = nullptr;
static bool _filter_metadata_confs(const string &prefix, std::map<string, bool> &configs,
- map<string, bufferlist> &pairs, map<string, bufferlist> *res);
+ const map<string, bufferlist> &pairs, map<string, bufferlist> *res);
// unit test mock helpers
static ImageCtx* create(const std::string &image_name,
void cancel_async_requests();
void cancel_async_requests(Context *on_finish);
- void apply_metadata_confs();
+ void apply_metadata(const std::map<std::string, bufferlist> &meta);
ExclusiveLock<ImageCtx> *create_exclusive_lock();
ObjectMap *create_object_map(uint64_t snap_id);
#include "librbd/image/CloseRequest.h"
#include "librbd/image/RefreshRequest.h"
#include "librbd/image/SetSnapRequest.h"
+#include <boost/algorithm/string/predicate.hpp>
+#include "include/assert.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
namespace librbd {
namespace image {
+namespace {
+
+static uint64_t MAX_METADATA_ITEMS = 128;
+
+}
+
using util::create_context_callback;
using util::create_rados_ack_callback;
template <typename I>
OpenRequest<I>::OpenRequest(I *image_ctx, Context *on_finish)
- : m_image_ctx(image_ctx), m_on_finish(on_finish), m_error_result(0) {
+ : m_image_ctx(image_ctx), m_on_finish(on_finish), m_error_result(0),
+ m_last_metadata_key(ImageCtx::METADATA_CONF_PREFIX) {
}
template <typename I>
m_image_ctx->old_format = true;
m_image_ctx->header_oid = util::old_header_name(m_image_ctx->name);
+ m_image_ctx->apply_metadata({});
+
send_register_watch();
}
return nullptr;
lderr(cct) << "failed to read striping metadata: " << cpp_strerror(*result)
<< dendl;
send_close_image(*result);
- } else {
- send_register_watch();
+ return nullptr;
+ }
+
+ m_image_ctx->init_layout();
+
+ send_v2_apply_metadata();
+ return nullptr;
+}
+
+template <typename I>
+void OpenRequest<I>::send_v2_apply_metadata() {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 10) << this << " " << __func__ << ": "
+ << "start_key=" << m_last_metadata_key << dendl;
+
+ librados::ObjectReadOperation op;
+ cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
+
+ using klass = OpenRequest<I>;
+ librados::AioCompletion *comp =
+ create_rados_ack_callback<klass, &klass::handle_v2_apply_metadata>(this);
+ m_out_bl.clear();
+ m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
+ &m_out_bl);
+ comp->release();
+}
+
+template <typename I>
+Context *OpenRequest<I>::handle_v2_apply_metadata(int *result) {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
+
+ std::map<std::string, bufferlist> metadata;
+ if (*result == 0) {
+ bufferlist::iterator it = m_out_bl.begin();
+ *result = cls_client::metadata_list_finish(&it, &metadata);
+ }
+
+ if (*result == -EOPNOTSUPP || *result == -EIO) {
+ ldout(cct, 10) << "config metadata not supported by OSD" << dendl;
+ } else if (*result < 0) {
+ lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(*result)
+ << dendl;
+ send_close_image(*result);
+ return nullptr;
}
+
+ if (!metadata.empty()) {
+ m_metadata.insert(metadata.begin(), metadata.end());
+ m_last_metadata_key = metadata.rbegin()->first;
+ if (boost::starts_with(m_last_metadata_key,
+ ImageCtx::METADATA_CONF_PREFIX)) {
+ send_v2_apply_metadata();
+ return nullptr;
+ }
+ }
+
+ m_image_ctx->apply_metadata(m_metadata);
+
+ send_register_watch();
return nullptr;
}
void OpenRequest<I>::send_register_watch() {
m_image_ctx->init();
- if (!m_image_ctx->read_only) {
- CephContext *cct = m_image_ctx->cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
-
- using klass = OpenRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_register_watch>(this);
- m_image_ctx->register_watch(ctx);
- } else {
+ if (m_image_ctx->read_only) {
send_refresh();
+ return;
}
+
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 10) << this << " " << __func__ << dendl;
+
+ using klass = OpenRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_register_watch>(this);
+ m_image_ctx->register_watch(ctx);
}
template <typename I>
#include "include/int_types.h"
#include "include/buffer.h"
+#include <map>
+#include <string>
class Context;
*
* <start>
* |
- * | (v1) (read only)
- * |-----> V1_DETECT_HEADER . . . . . . . . . . . . . . . . .
- * | | .
- * | \-------------------------------\ .
- * | (v2) | .
- * \-----> V2_DETECT_HEADER | .
- * | | .
- * v | .
- * V2_GET_ID|NAME | .
- * | | .
- * v | .
- * V2_GET_IMMUTABLE_METADATA | .
- * | | .
- * v v .
- * V2_GET_STRIPE_UNIT_COUNT ----> REGISTER_WATCH .
- * . | .
- * . (read only) v .
- * . . . . . . . . . . . . . > REFRESH < . . . . .
- * . |
- * . |
- * . \--> SET_SNAP
- * (no snap) . |
- * . v
- * . . . > <finish>
- * ^
- * (on error) |
- * * * * * * * > CLOSE --------------------------------/
+ * | (v1)
+ * |-----> V1_DETECT_HEADER
+ * | |
+ * | \-------------------------------\
+ * | (v2) |
+ * \-----> V2_DETECT_HEADER |
+ * | |
+ * v |
+ * V2_GET_ID|NAME |
+ * | |
+ * v |
+ * V2_GET_IMMUTABLE_METADATA |
+ * | |
+ * v |
+ * V2_GET_STRIPE_UNIT_COUNT |
+ * | |
+ * v v
+ * /---> V2_APPLY_METADATA -------------> REGISTER_WATCH (skip if
+ * | | | read-only)
+ * \---------/ v
+ * REFRESH
+ * |
+ * v
+ * SET_SNAP (skip if no snap)
+ * |
+ * v
+ * <finish>
+ * ^
+ * (on error) |
+ * * * * * * * > CLOSE ------------------------/
*
* @endverbatim
*/
bufferlist m_out_bl;
int m_error_result;
+ std::string m_last_metadata_key;
+ std::map<std::string, bufferlist> m_metadata;
+
void send_v1_detect_header();
Context *handle_v1_detect_header(int *result);
void send_v2_get_stripe_unit_count();
Context *handle_v2_get_stripe_unit_count(int *result);
+ void send_v2_apply_metadata();
+ Context *handle_v2_apply_metadata(int *result);
+
void send_register_watch();
Context *handle_register_watch(int *result);