From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/rgw/rgw_sal_rados.cc | 1361 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1361 insertions(+) create mode 100644 src/rgw/rgw_sal_rados.cc (limited to 'src/rgw/rgw_sal_rados.cc') diff --git a/src/rgw/rgw_sal_rados.cc b/src/rgw/rgw_sal_rados.cc new file mode 100644 index 000000000..9a6c473b9 --- /dev/null +++ b/src/rgw/rgw_sal_rados.cc @@ -0,0 +1,1361 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include +#include +#include +#include + +#include "common/Clock.h" +#include "common/errno.h" + +#include "rgw_sal.h" +#include "rgw_sal_rados.h" +#include "rgw_bucket.h" +#include "rgw_multi.h" +#include "rgw_acl_s3.h" + +#include "rgw_zone.h" +#include "rgw_rest_conn.h" +#include "rgw_service.h" +#include "rgw_lc.h" +#include "services/svc_sys_obj.h" +#include "services/svc_zone.h" +#include "services/svc_tier_rados.h" +#include "cls/rgw/cls_rgw_client.h" + +#include "rgw_pubsub.h" + +#define dout_subsys ceph_subsys_rgw + +namespace rgw::sal { + +int RGWRadosUser::list_buckets(const DoutPrefixProvider *dpp, const string& marker, const string& end_marker, + uint64_t max, bool need_stats, RGWBucketList &buckets, + optional_yield y) +{ + RGWUserBuckets ulist; + bool is_truncated = false; + int ret; + + buckets.clear(); + ret = store->ctl()->user->list_buckets(dpp, info.user_id, marker, end_marker, max, + need_stats, &ulist, &is_truncated, y); + if (ret < 0) + return ret; + + buckets.set_truncated(is_truncated); + for (const auto& ent : ulist.get_buckets()) { + buckets.add(std::unique_ptr(new RGWRadosBucket(this->store, ent.second, this))); + } + + return 0; +} + +RGWBucket* RGWRadosUser::create_bucket(rgw_bucket& bucket, + ceph::real_time creation_time) +{ + return NULL; +} + +int RGWRadosUser::load_by_id(const DoutPrefixProvider *dpp, optional_yield y) + +{ + return store->ctl()->user->get_info_by_uid(dpp, info.user_id, &info, y); +} + +std::unique_ptr RGWRadosStore::get_object(const rgw_obj_key& k) +{ + return std::unique_ptr(new RGWRadosObject(this, k)); +} + +/* Placeholder */ +RGWObject *RGWRadosBucket::create_object(const rgw_obj_key &key) +{ + return nullptr; +} + +int RGWRadosBucket::remove_bucket(const DoutPrefixProvider *dpp, + bool delete_children, + bool forward_to_master, + req_info* req_info, optional_yield y) +{ + int ret; + + // Refresh info + ret = get_bucket_info(dpp, y); + if (ret < 0) + return ret; + + ListParams params; + params.list_versions = true; + params.allow_unordered = true; + + ListResults results; + + do { + results.objs.clear(); + + ret = list(dpp, params, 1000, results, y); + if (ret < 0) + return ret; + + if (!results.objs.empty() && !delete_children) { + ldpp_dout(dpp, -1) << "ERROR: could not remove non-empty bucket " << info.bucket.name << + dendl; + return -ENOTEMPTY; + } + + for (const auto& obj : results.objs) { + rgw_obj_key key(obj.key); + /* xxx dang */ + ret = rgw_remove_object(dpp, store, info, info.bucket, key); + if (ret < 0 && ret != -ENOENT) { + return ret; + } + } + } while(results.is_truncated); + + ret = abort_bucket_multiparts(dpp, store, store->ctx(), info); + if (ret < 0) { + return ret; + } + + // remove lifecycle config, if any (XXX note could be made generic) + (void) store->getRados()->get_lc()->remove_bucket_config( + this->info, get_attrs()); + + ret = store->ctl()->bucket->sync_user_stats(dpp, info.owner, info, y); + if (ret < 0) { + ldout(store->ctx(), 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl; + } + + RGWObjVersionTracker ot; + + // if we deleted children above we will force delete, as any that + // remain is detrius from a prior bug + ret = store->getRados()->delete_bucket(info, ot, y, dpp, !delete_children); + if (ret < 0) { + ldpp_dout(dpp, -1) << "ERROR: could not remove bucket " << + info.bucket.name << dendl; + return ret; + } + + // if bucket has notification definitions associated with it + // they should be removed (note that any pending notifications on the bucket are still going to be sent) + RGWPubSub ps(store, info.owner.tenant); + RGWPubSub::Bucket ps_bucket(&ps, info.bucket); + const auto ps_ret = ps_bucket.remove_notifications(dpp, y); + if (ps_ret < 0 && ps_ret != -ENOENT) { + lderr(store->ctx()) << "ERROR: unable to remove notifications from bucket. ret=" << ps_ret << dendl; + } + + ret = store->ctl()->bucket->unlink_bucket(info.owner, info.bucket, y, dpp, false); + if (ret < 0) { + ldpp_dout(dpp, -1) << "ERROR: unable to remove user bucket information" << dendl; + } + + if (forward_to_master) { + bufferlist in_data; + ret = store->forward_request_to_master(dpp, owner, &ot.read_version, in_data, nullptr, *req_info, y); + if (ret < 0) { + if (ret == -ENOENT) { + /* adjust error, we want to return with NoSuchBucket and not + * NoSuchKey */ + ret = -ERR_NO_SUCH_BUCKET; + } + return ret; + } + } + + return ret; +} + +int RGWRadosBucket::get_bucket_info(const DoutPrefixProvider *dpp, optional_yield y) +{ + auto obj_ctx = store->svc()->sysobj->init_obj_ctx(); + RGWSI_MetaBackend_CtxParams bectx_params = RGWSI_MetaBackend_CtxParams_SObj(&obj_ctx); + RGWObjVersionTracker ep_ot; + int ret = store->ctl()->bucket->read_bucket_info(info.bucket, &info, y, dpp, + RGWBucketCtl::BucketInstance::GetParams() + .set_mtime(&mtime) + .set_attrs(&attrs) + .set_bectx_params(bectx_params), + &ep_ot); + if (ret == 0) { + bucket_version = ep_ot.read_version; + ent.placement_rule = info.placement_rule; + ent.bucket = info.bucket; // we looked up bucket_id + } + return ret; +} + +int RGWRadosBucket::load_by_name(const DoutPrefixProvider *dpp, const std::string& tenant, const std::string& bucket_name, const std::string bucket_instance_id, RGWSysObjectCtx *rctx, optional_yield y) +{ + info.bucket.tenant = tenant; + info.bucket.name = bucket_name; + info.bucket.bucket_id = bucket_instance_id; + ent.bucket = info.bucket; + + if (bucket_instance_id.empty()) { + return get_bucket_info(dpp, y); + } + + return store->getRados()->get_bucket_instance_info(*rctx, info.bucket, info, NULL, &attrs, y, dpp); +} + +int RGWRadosBucket::get_bucket_stats(const DoutPrefixProvider *dpp, RGWBucketInfo& bucket_info, int shard_id, + std::string *bucket_ver, std::string *master_ver, + std::map& stats, + std::string *max_marker, bool *syncstopped) +{ + return store->getRados()->get_bucket_stats(dpp, bucket_info, shard_id, bucket_ver, master_ver, stats, max_marker, syncstopped); +} + +int RGWRadosBucket::read_bucket_stats(const DoutPrefixProvider *dpp, optional_yield y) +{ + int ret = store->ctl()->bucket->read_bucket_stats(info.bucket, &ent, y, dpp); + info.placement_rule = ent.placement_rule; + return ret; +} + +int RGWRadosBucket::sync_user_stats(const DoutPrefixProvider *dpp, optional_yield y) +{ + return store->ctl()->bucket->sync_user_stats(dpp, owner->get_id(), info, y); +} + +int RGWRadosBucket::update_container_stats(const DoutPrefixProvider *dpp) +{ + int ret; + map m; + + m[info.bucket.name] = ent; + ret = store->getRados()->update_containers_stats(m, dpp); + if (!ret) + return -EEXIST; + if (ret < 0) + return ret; + + map::iterator iter = m.find(info.bucket.name); + if (iter == m.end()) + return -EINVAL; + + ent.count = iter->second.count; + ent.size = iter->second.size; + ent.size_rounded = iter->second.size_rounded; + ent.creation_time = iter->second.creation_time; + ent.placement_rule = std::move(iter->second.placement_rule); + + info.creation_time = ent.creation_time; + info.placement_rule = ent.placement_rule; + + return 0; +} + +int RGWRadosBucket::check_bucket_shards(const DoutPrefixProvider *dpp) +{ + return store->getRados()->check_bucket_shards(info, info.bucket, get_count(), dpp); +} + +int RGWRadosBucket::link(const DoutPrefixProvider *dpp, RGWUser* new_user, optional_yield y) +{ + RGWBucketEntryPoint ep; + ep.bucket = info.bucket; + ep.owner = new_user->get_user(); + ep.creation_time = get_creation_time(); + ep.linked = true; + RGWAttrs ep_attrs; + rgw_ep_info ep_data{ep, ep_attrs}; + + return store->ctl()->bucket->link_bucket(new_user->get_user(), info.bucket, + ceph::real_time(), y, dpp, true, &ep_data); +} + +int RGWRadosBucket::unlink(RGWUser* new_user, optional_yield y) +{ + return -1; +} + +int RGWRadosBucket::chown(RGWUser* new_user, RGWUser* old_user, optional_yield y, const DoutPrefixProvider *dpp) +{ + string obj_marker; + + return store->ctl()->bucket->chown(store, info, new_user->get_user(), + old_user->get_display_name(), obj_marker, y, dpp); +} + +int RGWRadosBucket::put_instance_info(const DoutPrefixProvider *dpp, bool exclusive, ceph::real_time _mtime) +{ + mtime = _mtime; + return store->getRados()->put_bucket_instance_info(info, exclusive, mtime, &attrs, dpp); +} + +/* Make sure to call get_bucket_info() if you need it first */ +bool RGWRadosBucket::is_owner(RGWUser* user) +{ + return (info.owner.compare(user->get_user()) == 0); +} + +int RGWRadosBucket::check_empty(const DoutPrefixProvider *dpp, optional_yield y) +{ + return store->getRados()->check_bucket_empty(dpp, info, y); +} + +int RGWRadosBucket::check_quota(RGWQuotaInfo& user_quota, RGWQuotaInfo& bucket_quota, uint64_t obj_size, + optional_yield y, bool check_size_only) +{ + return store->getRados()->check_quota(owner->get_user(), get_key(), + user_quota, bucket_quota, obj_size, y, check_size_only); +} + +int RGWRadosBucket::set_instance_attrs(const DoutPrefixProvider *dpp, RGWAttrs& attrs, optional_yield y) +{ + return store->ctl()->bucket->set_bucket_instance_attrs(get_info(), + attrs, &get_info().objv_tracker, y, dpp); +} + +int RGWRadosBucket::try_refresh_info(const DoutPrefixProvider *dpp, ceph::real_time *pmtime) +{ + return store->getRados()->try_refresh_bucket_info(info, pmtime, dpp, &attrs); +} + +int RGWRadosBucket::read_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch, + uint32_t max_entries, bool *is_truncated, + RGWUsageIter& usage_iter, + map& usage) +{ + return store->getRados()->read_usage(dpp, owner->get_id(), get_name(), start_epoch, + end_epoch, max_entries, is_truncated, + usage_iter, usage); +} + +int RGWRadosBucket::set_acl(const DoutPrefixProvider *dpp, RGWAccessControlPolicy &acl, optional_yield y) +{ + bufferlist aclbl; + + acls = acl; + acl.encode(aclbl); + + return store->ctl()->bucket->set_acl(acl.get_owner(), info.bucket, info, aclbl, y, dpp); +} + +std::unique_ptr RGWRadosBucket::get_object(const rgw_obj_key& k) +{ + return std::unique_ptr(new RGWRadosObject(this->store, k, this)); +} + +int RGWRadosBucket::list(const DoutPrefixProvider *dpp, ListParams& params, int max, ListResults& results, optional_yield y) +{ + RGWRados::Bucket target(store->getRados(), get_info()); + if (params.shard_id >= 0) { + target.set_shard_id(params.shard_id); + } + RGWRados::Bucket::List list_op(&target); + + list_op.params.prefix = params.prefix; + list_op.params.delim = params.delim; + list_op.params.marker = params.marker; + list_op.params.ns = params.ns; + list_op.params.end_marker = params.end_marker; + list_op.params.list_versions = params.list_versions; + list_op.params.allow_unordered = params.allow_unordered; + + int ret = list_op.list_objects(dpp, max, &results.objs, &results.common_prefixes, &results.is_truncated, y); + if (ret >= 0) { + results.next_marker = list_op.get_next_marker(); + params.marker = results.next_marker; + } + + return ret; +} + +std::unique_ptr RGWRadosStore::get_user(const rgw_user &u) +{ + return std::unique_ptr(new RGWRadosUser(this, u)); +} + +//RGWBucket *RGWRadosStore::create_bucket(RGWUser &u, const rgw_bucket &b) +//{ + //if (!bucket) { + //bucket = new RGWRadosBucket(this, u, b); + //} +// + //return bucket; +//} +// +void RGWRadosStore::finalize(void) +{ + if (rados) + rados->finalize(); +} + +int RGWObject::range_to_ofs(uint64_t obj_size, int64_t &ofs, int64_t &end) +{ + if (ofs < 0) { + ofs += obj_size; + if (ofs < 0) + ofs = 0; + end = obj_size - 1; + } else if (end < 0) { + end = obj_size - 1; + } + + if (obj_size > 0) { + if (ofs >= (off_t)obj_size) { + return -ERANGE; + } + if (end >= (off_t)obj_size) { + end = obj_size - 1; + } + } + return 0; +} + +int RGWRadosObject::get_obj_state(const DoutPrefixProvider *dpp, RGWObjectCtx *rctx, RGWBucket& bucket, RGWObjState **state, optional_yield y, bool follow_olh) +{ + //rgw_obj obj(bucket.get_key(), key); + //obj.set_in_extra_data(in_extra_data); + //obj.index_hash_source = index_hash_source; + return store->getRados()->get_obj_state(dpp, rctx, bucket.get_info(), get_obj(), state, follow_olh, y); +} + +int RGWRadosObject::read_attrs(RGWRados::Object::Read &read_op, optional_yield y, const DoutPrefixProvider *dpp, rgw_obj *target_obj) +{ + read_op.params.attrs = &attrs; + read_op.params.target_obj = target_obj; + read_op.params.obj_size = &obj_size; + read_op.params.lastmod = &mtime; + + return read_op.prepare(y, dpp); +} + +int RGWRadosObject::set_obj_attrs(const DoutPrefixProvider *dpp, RGWObjectCtx* rctx, RGWAttrs* setattrs, RGWAttrs* delattrs, optional_yield y, rgw_obj* target_obj) +{ + RGWAttrs empty; + rgw_obj target = get_obj(); + + if (!target_obj) + target_obj = ⌖ + + return store->getRados()->set_attrs(dpp, rctx, + bucket->get_info(), + *target_obj, + setattrs ? *setattrs : empty, + delattrs ? delattrs : nullptr, + y); +} + +int RGWRadosObject::get_obj_attrs(RGWObjectCtx *rctx, optional_yield y, const DoutPrefixProvider *dpp, rgw_obj* target_obj) +{ + RGWRados::Object op_target(store->getRados(), bucket->get_info(), *rctx, get_obj()); + RGWRados::Object::Read read_op(&op_target); + + return read_attrs(read_op, y, dpp, target_obj); +} + +int RGWRadosObject::modify_obj_attrs(RGWObjectCtx *rctx, const char *attr_name, bufferlist& attr_val, optional_yield y, const DoutPrefixProvider *dpp) +{ + rgw_obj target = get_obj(); + int r = get_obj_attrs(rctx, y, dpp, &target); + if (r < 0) { + return r; + } + set_atomic(rctx); + attrs[attr_name] = attr_val; + return set_obj_attrs(dpp, rctx, &attrs, nullptr, y, &target); +} + +int RGWRadosObject::delete_obj_attrs(const DoutPrefixProvider *dpp, RGWObjectCtx *rctx, const char *attr_name, optional_yield y) +{ + RGWAttrs rmattr; + bufferlist bl; + + set_atomic(rctx); + rmattr[attr_name] = bl; + return set_obj_attrs(dpp, rctx, nullptr, &rmattr, y); +} + +int RGWRadosObject::copy_obj_data(RGWObjectCtx& rctx, RGWBucket* dest_bucket, + RGWObject* dest_obj, + uint16_t olh_epoch, + std::string* petag, + const DoutPrefixProvider *dpp, + optional_yield y) +{ + RGWAttrs attrset; + RGWRados::Object op_target(store->getRados(), dest_bucket->get_info(), rctx, get_obj()); + RGWRados::Object::Read read_op(&op_target); + + int ret = read_attrs(read_op, y, dpp); + if (ret < 0) + return ret; + + attrset = attrs; + + attrset.erase(RGW_ATTR_ID_TAG); + attrset.erase(RGW_ATTR_TAIL_TAG); + + return store->getRados()->copy_obj_data(rctx, dest_bucket, + dest_bucket->get_info().placement_rule, read_op, + obj_size - 1, dest_obj, NULL, mtime, attrset, 0, + real_time(), NULL, dpp, y); +} + +void RGWRadosObject::set_atomic(RGWObjectCtx *rctx) const +{ + rgw_obj obj = get_obj(); + store->getRados()->set_atomic(rctx, obj); +} + +void RGWRadosObject::set_prefetch_data(RGWObjectCtx *rctx) +{ + rgw_obj obj = get_obj(); + store->getRados()->set_prefetch_data(rctx, obj); +} + +bool RGWRadosObject::is_expired() { + auto iter = attrs.find(RGW_ATTR_DELETE_AT); + if (iter != attrs.end()) { + utime_t delete_at; + try { + auto bufit = iter->second.cbegin(); + decode(delete_at, bufit); + } catch (buffer::error& err) { + ldout(store->ctx(), 0) << "ERROR: " << __func__ << ": failed to decode " RGW_ATTR_DELETE_AT " attr" << dendl; + return false; + } + + if (delete_at <= ceph_clock_now() && !delete_at.is_zero()) { + return true; + } + } + + return false; +} + +void RGWRadosObject::gen_rand_obj_instance_name() +{ + store->getRados()->gen_rand_obj_instance_name(&key); +} + +void RGWRadosObject::raw_obj_to_obj(const rgw_raw_obj& raw_obj) +{ + rgw_obj tobj = get_obj(); + RGWSI_Tier_RADOS::raw_obj_to_obj(get_bucket()->get_key(), raw_obj, &tobj); + set_key(tobj.key); +} + +void RGWRadosObject::get_raw_obj(rgw_raw_obj* raw_obj) +{ + store->getRados()->obj_to_raw((bucket->get_info()).placement_rule, get_obj(), raw_obj); +} + +int RGWRadosObject::omap_get_vals_by_keys(const DoutPrefixProvider *dpp, + const std::string& oid, + const std::set& keys, + RGWAttrs *vals) +{ + int ret; + rgw_raw_obj head_obj; + librados::IoCtx cur_ioctx; + rgw_obj obj = get_obj(); + + store->getRados()->obj_to_raw(bucket->get_placement_rule(), obj, &head_obj); + ret = store->get_obj_head_ioctx(dpp, bucket->get_info(), obj, &cur_ioctx); + if (ret < 0) { + return ret; + } + + return cur_ioctx.omap_get_vals_by_keys(oid, keys, vals); +} + +int RGWRadosObject::omap_set_val_by_key(const DoutPrefixProvider *dpp, const std::string& key, bufferlist& val, + bool must_exist, optional_yield y) +{ + rgw_raw_obj raw_meta_obj; + rgw_obj obj = get_obj(); + + store->getRados()->obj_to_raw(bucket->get_placement_rule(), obj, &raw_meta_obj); + + auto obj_ctx = store->svc()->sysobj->init_obj_ctx(); + auto sysobj = obj_ctx.get_obj(raw_meta_obj); + + return sysobj.omap().set_must_exist(must_exist).set(dpp, key, val, y); +} + +MPSerializer* RGWRadosObject::get_serializer(const DoutPrefixProvider *dpp, const std::string& lock_name) +{ + return new MPRadosSerializer(dpp, store, this, lock_name); +} + +int RGWRadosObject::transition(RGWObjectCtx& rctx, + RGWBucket* bucket, + const rgw_placement_rule& placement_rule, + const real_time& mtime, + uint64_t olh_epoch, + const DoutPrefixProvider *dpp, + optional_yield y) +{ + return store->getRados()->transition_obj(rctx, bucket, *this, placement_rule, mtime, olh_epoch, dpp, y); +} + +int RGWRadosObject::get_max_chunk_size(const DoutPrefixProvider *dpp, rgw_placement_rule placement_rule, uint64_t *max_chunk_size, uint64_t *alignment) +{ + return store->getRados()->get_max_chunk_size(placement_rule, get_obj(), max_chunk_size, dpp, alignment); +} + +void RGWRadosObject::get_max_aligned_size(uint64_t size, uint64_t alignment, + uint64_t *max_size) +{ + store->getRados()->get_max_aligned_size(size, alignment, max_size); +} + +bool RGWRadosObject::placement_rules_match(rgw_placement_rule& r1, rgw_placement_rule& r2) +{ + rgw_obj obj; + rgw_pool p1, p2; + + obj = get_obj(); + + if (r1 == r2) + return true; + + if (!store->getRados()->get_obj_data_pool(r1, obj, &p1)) { + return false; + } + if (!store->getRados()->get_obj_data_pool(r2, obj, &p2)) { + return false; + } + + return p1 == p2; +} + +std::unique_ptr RGWRadosObject::get_read_op(RGWObjectCtx *ctx) +{ + return std::unique_ptr(new RGWRadosObject::RadosReadOp(this, ctx)); +} + +RGWRadosObject::RadosReadOp::RadosReadOp(RGWRadosObject *_source, RGWObjectCtx *_rctx) : + source(_source), + rctx(_rctx), + op_target(_source->store->getRados(), + _source->get_bucket()->get_info(), + *static_cast(rctx), + _source->get_obj()), + parent_op(&op_target) +{ } + +int RGWRadosObject::RadosReadOp::prepare(optional_yield y, const DoutPrefixProvider *dpp) +{ + uint64_t obj_size; + + parent_op.conds.mod_ptr = params.mod_ptr; + parent_op.conds.unmod_ptr = params.unmod_ptr; + parent_op.conds.high_precision_time = params.high_precision_time; + parent_op.conds.mod_zone_id = params.mod_zone_id; + parent_op.conds.mod_pg_ver = params.mod_pg_ver; + parent_op.conds.if_match = params.if_match; + parent_op.conds.if_nomatch = params.if_nomatch; + parent_op.params.lastmod = params.lastmod; + parent_op.params.target_obj = params.target_obj; + parent_op.params.obj_size = &obj_size; + parent_op.params.attrs = &source->get_attrs(); + + int ret = parent_op.prepare(y, dpp); + if (ret < 0) + return ret; + + source->set_key(parent_op.state.obj.key); + source->set_obj_size(obj_size); + result.head_obj = parent_op.state.head_obj; + + return ret; +} + +int RGWRadosObject::RadosReadOp::read(int64_t ofs, int64_t end, bufferlist& bl, optional_yield y, const DoutPrefixProvider *dpp) +{ + return parent_op.read(ofs, end, bl, y, dpp); +} + +int RGWRadosObject::RadosReadOp::get_manifest(const DoutPrefixProvider *dpp, RGWObjManifest **pmanifest, + optional_yield y) +{ + return op_target.get_manifest(dpp, pmanifest, y); +} + +int RGWRadosObject::RadosReadOp::get_attr(const DoutPrefixProvider *dpp, const char *name, bufferlist& dest, optional_yield y) +{ + return parent_op.get_attr(dpp, name, dest, y); +} + +int RGWRadosObject::delete_object(const DoutPrefixProvider *dpp, + RGWObjectCtx* obj_ctx, + ACLOwner obj_owner, + ACLOwner bucket_owner, + ceph::real_time unmod_since, + bool high_precision_time, + uint64_t epoch, + std::string& version_id, + optional_yield y, + bool prevent_versioning) +{ + int ret = 0; + RGWRados::Object del_target(store->getRados(), bucket->get_info(), *obj_ctx, get_obj()); + RGWRados::Object::Delete del_op(&del_target); + + del_op.params.olh_epoch = epoch; + del_op.params.marker_version_id = version_id; + del_op.params.bucket_owner = bucket_owner.get_id(); + del_op.params.versioning_status = + prevent_versioning ? 0 : bucket->get_info().versioning_status(); + del_op.params.obj_owner = obj_owner; + del_op.params.unmod_since = unmod_since; + del_op.params.high_precision_time = high_precision_time; + + ret = del_op.delete_obj(y, dpp); + if (ret >= 0) { + delete_marker = del_op.result.delete_marker; + version_id = del_op.result.version_id; + } + + return ret; +} + +int RGWRadosObject::copy_object(RGWObjectCtx& obj_ctx, + RGWUser* user, + req_info *info, + const rgw_zone_id& source_zone, + rgw::sal::RGWObject* dest_object, + rgw::sal::RGWBucket* dest_bucket, + rgw::sal::RGWBucket* src_bucket, + const rgw_placement_rule& dest_placement, + ceph::real_time *src_mtime, + ceph::real_time *mtime, + const ceph::real_time *mod_ptr, + const ceph::real_time *unmod_ptr, + bool high_precision_time, + const char *if_match, + const char *if_nomatch, + AttrsMod attrs_mod, + bool copy_if_newer, + RGWAttrs& attrs, + RGWObjCategory category, + uint64_t olh_epoch, + boost::optional delete_at, + string *version_id, + string *tag, + string *etag, + void (*progress_cb)(off_t, void *), + void *progress_data, + const DoutPrefixProvider *dpp, + optional_yield y) +{ + return store->getRados()->copy_obj(obj_ctx, + user->get_id(), + info, + source_zone, + dest_object, + this, + dest_bucket, + src_bucket, + dest_placement, + src_mtime, + mtime, + mod_ptr, + unmod_ptr, + high_precision_time, + if_match, + if_nomatch, + static_cast(attrs_mod), + copy_if_newer, + attrs, + category, + olh_epoch, + (delete_at ? *delete_at : real_time()), + version_id, + tag, + etag, + progress_cb, + progress_data, + dpp, + y); +} + +int RGWRadosObject::RadosReadOp::iterate(const DoutPrefixProvider *dpp, int64_t ofs, int64_t end, RGWGetDataCB *cb, optional_yield y) +{ + return parent_op.iterate(dpp, ofs, end, cb, y); +} + +std::unique_ptr RGWRadosObject::get_write_op(RGWObjectCtx* ctx) +{ + return std::unique_ptr(new RGWRadosObject::RadosWriteOp(this, ctx)); +} + +RGWRadosObject::RadosWriteOp::RadosWriteOp(RGWRadosObject* _source, RGWObjectCtx* _rctx) : + source(_source), + rctx(_rctx), + op_target(_source->store->getRados(), + _source->get_bucket()->get_info(), + *static_cast(rctx), + _source->get_obj()), + parent_op(&op_target) +{ } + +int RGWRadosObject::RadosWriteOp::prepare(optional_yield y) +{ + op_target.set_versioning_disabled(params.versioning_disabled); + op_target.set_meta_placement_rule(params.pmeta_placement_rule); + parent_op.meta.mtime = params.mtime; + parent_op.meta.rmattrs = params.rmattrs; + parent_op.meta.data = params.data; + parent_op.meta.manifest = params.manifest; + parent_op.meta.ptag = params.ptag; + parent_op.meta.remove_objs = params.remove_objs; + parent_op.meta.set_mtime = params.set_mtime; + parent_op.meta.owner = params.owner.get_id(); + parent_op.meta.category = params.category; + parent_op.meta.flags = params.flags; + parent_op.meta.if_match = params.if_match; + parent_op.meta.if_nomatch = params.if_nomatch; + parent_op.meta.olh_epoch = params.olh_epoch; + parent_op.meta.delete_at = params.delete_at; + parent_op.meta.canceled = params.canceled; + parent_op.meta.user_data = params.user_data; + parent_op.meta.zones_trace = params.zones_trace; + parent_op.meta.modify_tail = params.modify_tail; + parent_op.meta.completeMultipart = params.completeMultipart; + parent_op.meta.appendable = params.appendable; + + return 0; +} + +int RGWRadosObject::RadosWriteOp::write_meta(const DoutPrefixProvider *dpp, uint64_t size, uint64_t accounted_size, optional_yield y) +{ + int ret = parent_op.write_meta(dpp, size, accounted_size, *params.attrs, y); + params.canceled = parent_op.meta.canceled; + + return ret; +} + +int RGWRadosObject::swift_versioning_restore(RGWObjectCtx* obj_ctx, + bool& restored, + const DoutPrefixProvider *dpp) +{ + return store->getRados()->swift_versioning_restore(*obj_ctx, + bucket->get_owner()->get_id(), + bucket, + this, + restored, + dpp); +} + +int RGWRadosObject::swift_versioning_copy(RGWObjectCtx* obj_ctx, + const DoutPrefixProvider *dpp, + optional_yield y) +{ + return store->getRados()->swift_versioning_copy(*obj_ctx, + bucket->get_info().owner, + bucket, + this, + dpp, + y); +} + +int RGWRadosStore::get_bucket(const DoutPrefixProvider *dpp, RGWUser* u, const rgw_bucket& b, std::unique_ptr* bucket, optional_yield y) +{ + int ret; + RGWBucket* bp; + + bp = new RGWRadosBucket(this, b, u); + ret = bp->get_bucket_info(dpp, y); + if (ret < 0) { + delete bp; + return ret; + } + + bucket->reset(bp); + return 0; +} + +int RGWRadosStore::get_bucket(RGWUser* u, const RGWBucketInfo& i, std::unique_ptr* bucket) +{ + RGWBucket* bp; + + bp = new RGWRadosBucket(this, i, u); + /* Don't need to fetch the bucket info, use the provided one */ + + bucket->reset(bp); + return 0; +} + +int RGWRadosStore::get_bucket(const DoutPrefixProvider *dpp, RGWUser* u, const std::string& tenant, const std::string&name, std::unique_ptr* bucket, optional_yield y) +{ + rgw_bucket b; + + b.tenant = tenant; + b.name = name; + + return get_bucket(dpp, u, b, bucket, y); +} + +static int decode_policy(const DoutPrefixProvider *dpp, + CephContext *cct, + bufferlist& bl, + RGWAccessControlPolicy *policy) +{ + auto iter = bl.cbegin(); + try { + policy->decode(iter); + } catch (buffer::error& err) { + ldpp_dout(dpp, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl; + return -EIO; + } + if (cct->_conf->subsys.should_gather()) { + ldpp_dout(dpp, 15) << __func__ << " Read AccessControlPolicy"; + RGWAccessControlPolicy_S3 *s3policy = static_cast(policy); + s3policy->to_xml(*_dout); + *_dout << dendl; + } + return 0; +} + +static int rgw_op_get_bucket_policy_from_attr(const DoutPrefixProvider *dpp, RGWRadosStore *store, + RGWUser& user, + RGWAttrs& bucket_attrs, + RGWAccessControlPolicy *policy, + optional_yield y) +{ + auto aiter = bucket_attrs.find(RGW_ATTR_ACL); + + if (aiter != bucket_attrs.end()) { + int ret = decode_policy(dpp, store->ctx(), aiter->second, policy); + if (ret < 0) + return ret; + } else { + ldout(store->ctx(), 0) << "WARNING: couldn't find acl header for bucket, generating default" << dendl; + /* object exists, but policy is broken */ + int r = user.load_by_id(dpp, y); + if (r < 0) + return r; + + policy->create_default(user.get_user(), user.get_display_name()); + } + return 0; +} + +bool RGWRadosStore::is_meta_master() +{ + return svc()->zone->is_meta_master(); +} + +int RGWRadosStore::forward_request_to_master(const DoutPrefixProvider *dpp, + RGWUser* user, obj_version *objv, + bufferlist& in_data, + JSONParser *jp, req_info& info, + optional_yield y) +{ + if (is_meta_master()) { + /* We're master, don't forward */ + return 0; + } + + if (!svc()->zone->get_master_conn()) { + ldout(ctx(), 0) << "rest connection is invalid" << dendl; + return -EINVAL; + } + ldpp_dout(dpp, 0) << "sending request to master zonegroup" << dendl; + bufferlist response; + string uid_str = user->get_id().to_str(); +#define MAX_REST_RESPONSE (128 * 1024) // we expect a very small response + int ret = svc()->zone->get_master_conn()->forward(dpp, rgw_user(uid_str), info, + objv, MAX_REST_RESPONSE, + &in_data, &response, y); + if (ret < 0) + return ret; + + ldpp_dout(dpp, 20) << "response: " << response.c_str() << dendl; + if (jp && !jp->parse(response.c_str(), response.length())) { + ldout(ctx(), 0) << "failed parsing response from master zonegroup" << dendl; + return -EINVAL; + } + + return 0; +} + +int RGWRadosStore::defer_gc(const DoutPrefixProvider *dpp, RGWObjectCtx *rctx, RGWBucket* bucket, RGWObject* obj, optional_yield y) +{ + return rados->defer_gc(dpp, rctx, bucket->get_info(), obj->get_obj(), y); +} + +const RGWZoneGroup& RGWRadosStore::get_zonegroup() +{ + return rados->svc.zone->get_zonegroup(); +} + +int RGWRadosStore::get_zonegroup(const string& id, RGWZoneGroup& zonegroup) +{ + return rados->svc.zone->get_zonegroup(id, zonegroup); +} + +int RGWRadosStore::cluster_stat(RGWClusterStat& stats) +{ + rados_cluster_stat_t rados_stats; + int ret; + + ret = rados->get_rados_handle()->cluster_stat(rados_stats); + if (ret < 0) + return ret; + + stats.kb = rados_stats.kb; + stats.kb_used = rados_stats.kb_used; + stats.kb_avail = rados_stats.kb_avail; + stats.num_objects = rados_stats.num_objects; + + return ret; +} + +int RGWRadosStore::create_bucket(const DoutPrefixProvider *dpp, + RGWUser& u, const rgw_bucket& b, + const string& zonegroup_id, + rgw_placement_rule& placement_rule, + string& swift_ver_location, + const RGWQuotaInfo * pquota_info, + const RGWAccessControlPolicy& policy, + RGWAttrs& attrs, + RGWBucketInfo& info, + obj_version& ep_objv, + bool exclusive, + bool obj_lock_enabled, + bool *existed, + req_info& req_info, + std::unique_ptr* bucket_out, + optional_yield y) +{ + int ret; + bufferlist in_data; + RGWBucketInfo master_info; + rgw_bucket *pmaster_bucket; + uint32_t *pmaster_num_shards; + real_time creation_time; + std::unique_ptr bucket; + obj_version objv, *pobjv = NULL; + + /* If it exists, look it up; otherwise create it */ + ret = get_bucket(dpp, &u, b, &bucket, y); + if (ret < 0 && ret != -ENOENT) + return ret; + + if (ret != -ENOENT) { + RGWAccessControlPolicy old_policy(ctx()); + *existed = true; + if (swift_ver_location.empty()) { + swift_ver_location = bucket->get_info().swift_ver_location; + } + placement_rule.inherit_from(bucket->get_info().placement_rule); + + // don't allow changes to the acl policy + int r = rgw_op_get_bucket_policy_from_attr(dpp, this, u, bucket->get_attrs(), + &old_policy, y); + if (r >= 0 && old_policy != policy) { + bucket_out->swap(bucket); + return -EEXIST; + } + } else { + bucket = std::unique_ptr(new RGWRadosBucket(this, b, &u)); + *existed = false; + bucket->set_attrs(attrs); + } + + if (!svc()->zone->is_meta_master()) { + JSONParser jp; + ret = forward_request_to_master(dpp, &u, NULL, in_data, &jp, req_info, y); + if (ret < 0) { + return ret; + } + + JSONDecoder::decode_json("entry_point_object_ver", ep_objv, &jp); + JSONDecoder::decode_json("object_ver", objv, &jp); + JSONDecoder::decode_json("bucket_info", master_info, &jp); + ldpp_dout(dpp, 20) << "parsed: objv.tag=" << objv.tag << " objv.ver=" << objv.ver << dendl; + std::time_t ctime = ceph::real_clock::to_time_t(master_info.creation_time); + ldpp_dout(dpp, 20) << "got creation time: << " << std::put_time(std::localtime(&ctime), "%F %T") << dendl; + pmaster_bucket= &master_info.bucket; + creation_time = master_info.creation_time; + pmaster_num_shards = &master_info.layout.current_index.layout.normal.num_shards; + pobjv = &objv; + if (master_info.obj_lock_enabled()) { + info.flags = BUCKET_VERSIONED | BUCKET_OBJ_LOCK_ENABLED; + } + } else { + pmaster_bucket = NULL; + pmaster_num_shards = NULL; + if (obj_lock_enabled) + info.flags = BUCKET_VERSIONED | BUCKET_OBJ_LOCK_ENABLED; + } + + std::string zid = zonegroup_id; + if (zid.empty()) { + zid = svc()->zone->get_zonegroup().get_id(); + } + + if (*existed) { + rgw_placement_rule selected_placement_rule; + ret = svc()->zone->select_bucket_placement(dpp, u.get_info(), + zid, placement_rule, + &selected_placement_rule, nullptr, y); + if (selected_placement_rule != info.placement_rule) { + ret = -EEXIST; + bucket_out->swap(bucket); + return ret; + } + } else { + + ret = getRados()->create_bucket(u.get_info(), bucket->get_key(), + zid, placement_rule, swift_ver_location, + pquota_info, attrs, + info, pobjv, &ep_objv, creation_time, + pmaster_bucket, pmaster_num_shards, y, dpp, exclusive); + if (ret == -EEXIST) { + *existed = true; + ret = 0; + } else if (ret != 0) { + return ret; + } + } + + bucket->set_version(ep_objv); + bucket->get_info() = info; + + bucket_out->swap(bucket); + + return ret; +} + +std::unique_ptr RGWRadosStore::get_lifecycle(void) +{ + return std::unique_ptr(new RadosLifecycle(this)); +} + +int RGWRadosStore::delete_raw_obj(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj) +{ + return rados->delete_raw_obj(dpp, obj); +} + +void RGWRadosStore::get_raw_obj(const rgw_placement_rule& placement_rule, const rgw_obj& obj, rgw_raw_obj* raw_obj) +{ + rados->obj_to_raw(placement_rule, obj, raw_obj); +} + +int RGWRadosStore::get_raw_chunk_size(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, uint64_t* chunk_size) +{ + return rados->get_max_chunk_size(obj.pool, chunk_size, dpp); +} + +MPRadosSerializer::MPRadosSerializer(const DoutPrefixProvider *dpp, RGWRadosStore* store, RGWRadosObject* obj, const std::string& lock_name) : + lock(lock_name) +{ + rgw_pool meta_pool; + rgw_raw_obj raw_obj; + + obj->get_raw_obj(&raw_obj); + oid = raw_obj.oid; + store->getRados()->get_obj_data_pool(obj->get_bucket()->get_placement_rule(), + obj->get_obj(), &meta_pool); + store->getRados()->open_pool_ctx(dpp, meta_pool, ioctx, true); +} + +int MPRadosSerializer::try_lock(const DoutPrefixProvider *dpp, utime_t dur, optional_yield y) +{ + op.assert_exists(); + lock.set_duration(dur); + lock.lock_exclusive(&op); + int ret = rgw_rados_operate(dpp, ioctx, oid, &op, y); + if (! ret) { + locked = true; + } + return ret; +} + +LCRadosSerializer::LCRadosSerializer(RGWRadosStore* store, const std::string& _oid, const std::string& lock_name, const std::string& cookie) : + lock(lock_name), oid(_oid) +{ + ioctx = &store->getRados()->lc_pool_ctx; + lock.set_cookie(cookie); +} + +int LCRadosSerializer::try_lock(const DoutPrefixProvider *dpp, utime_t dur, optional_yield y) +{ + lock.set_duration(dur); + return lock.lock_exclusive(ioctx, oid); +} + +int RadosLifecycle::get_entry(const string& oid, const std::string& marker, + LCEntry& entry) +{ + cls_rgw_lc_entry cls_entry; + int ret = cls_rgw_lc_get_entry(*store->getRados()->get_lc_pool_ctx(), oid, marker, cls_entry); + + entry.bucket = cls_entry.bucket; + entry.start_time = cls_entry.start_time; + entry.status = cls_entry.status; + + return ret; +} + +int RadosLifecycle::get_next_entry(const string& oid, std::string& marker, + LCEntry& entry) +{ + cls_rgw_lc_entry cls_entry; + int ret = cls_rgw_lc_get_next_entry(*store->getRados()->get_lc_pool_ctx(), oid, marker, + cls_entry); + + entry.bucket = cls_entry.bucket; + entry.start_time = cls_entry.start_time; + entry.status = cls_entry.status; + + return ret; +} + +int RadosLifecycle::set_entry(const string& oid, const LCEntry& entry) +{ + cls_rgw_lc_entry cls_entry; + + cls_entry.bucket = entry.bucket; + cls_entry.start_time = entry.start_time; + cls_entry.status = entry.status; + + return cls_rgw_lc_set_entry(*store->getRados()->get_lc_pool_ctx(), oid, cls_entry); +} + +int RadosLifecycle::list_entries(const string& oid, const string& marker, + uint32_t max_entries, vector& entries) +{ + entries.clear(); + + vector cls_entries; + int ret = cls_rgw_lc_list(*store->getRados()->get_lc_pool_ctx(), oid, marker, max_entries, cls_entries); + + if (ret < 0) + return ret; + + for (auto& entry : cls_entries) { + entries.push_back(LCEntry(entry.bucket, entry.start_time, entry.status)); + } + + return ret; +} + +int RadosLifecycle::rm_entry(const string& oid, const LCEntry& entry) +{ + cls_rgw_lc_entry cls_entry; + + cls_entry.bucket = entry.bucket; + cls_entry.start_time = entry.start_time; + cls_entry.status = entry.status; + + return cls_rgw_lc_rm_entry(*store->getRados()->get_lc_pool_ctx(), oid, cls_entry); +} + +int RadosLifecycle::get_head(const string& oid, LCHead& head) +{ + cls_rgw_lc_obj_head cls_head; + int ret = cls_rgw_lc_get_head(*store->getRados()->get_lc_pool_ctx(), oid, cls_head); + + head.marker = cls_head.marker; + head.start_date = cls_head.start_date; + + return ret; +} + +int RadosLifecycle::put_head(const string& oid, const LCHead& head) +{ + cls_rgw_lc_obj_head cls_head; + + cls_head.marker = head.marker; + cls_head.start_date = head.start_date; + + return cls_rgw_lc_put_head(*store->getRados()->get_lc_pool_ctx(), oid, cls_head); +} + +LCSerializer* RadosLifecycle::get_serializer(const std::string& lock_name, const std::string& oid, const std::string& cookie) +{ + return new LCRadosSerializer(store, oid, lock_name, cookie); +} + +} // namespace rgw::sal + +rgw::sal::RGWRadosStore *RGWStoreManager::init_storage_provider(const DoutPrefixProvider *dpp, CephContext *cct, bool use_gc_thread, bool use_lc_thread, bool quota_threads, bool run_sync_thread, bool run_reshard_thread, bool use_cache, bool use_gc) +{ + RGWRados *rados = new RGWRados; + rgw::sal::RGWRadosStore *store = new rgw::sal::RGWRadosStore(); + + store->setRados(rados); + rados->set_store(store); + + if ((*rados).set_use_cache(use_cache) + .set_use_gc(use_gc) + .set_run_gc_thread(use_gc_thread) + .set_run_lc_thread(use_lc_thread) + .set_run_quota_threads(quota_threads) + .set_run_sync_thread(run_sync_thread) + .set_run_reshard_thread(run_reshard_thread) + .initialize(cct, dpp) < 0) { + delete store; + return NULL; + } + + return store; +} + +rgw::sal::RGWRadosStore *RGWStoreManager::init_raw_storage_provider(const DoutPrefixProvider *dpp, CephContext *cct) +{ + RGWRados *rados = new RGWRados; + rgw::sal::RGWRadosStore *store = new rgw::sal::RGWRadosStore(); + + store->setRados(rados); + rados->set_store(store); + + rados->set_context(cct); + + int ret = rados->init_svc(true, dpp); + if (ret < 0) { + ldout(cct, 0) << "ERROR: failed to init services (ret=" << cpp_strerror(-ret) << ")" << dendl; + delete store; + return nullptr; + } + + if (rados->init_rados() < 0) { + delete store; + return nullptr; + } + + return store; +} + +int rgw::sal::RGWRadosStore::get_obj_head_ioctx(const DoutPrefixProvider *dpp, const RGWBucketInfo& bucket_info, const rgw_obj& obj, librados::IoCtx *ioctx) +{ + return rados->get_obj_head_ioctx(dpp, bucket_info, obj, ioctx); +} + +void RGWStoreManager::close_storage(rgw::sal::RGWRadosStore *store) +{ + if (!store) + return; + + store->finalize(); + + delete store; +} -- cgit v1.2.3