]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/driver/rados/rgw_sal_rados.cc
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / rgw / driver / rados / rgw_sal_rados.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab ft=cpp
3
4/*
5 * Ceph - scalable distributed file system
6 *
7 * Copyright (C) 2020 Red Hat, Inc.
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
15
16#include <errno.h>
17#include <stdlib.h>
18#include <system_error>
1e59de90 19#include <filesystem>
f67539c2
TL
20#include <unistd.h>
21#include <sstream>
39ae355f 22#include <boost/algorithm/string.hpp>
1e59de90 23#include <boost/process.hpp>
f67539c2
TL
24
25#include "common/Clock.h"
26#include "common/errno.h"
27
28#include "rgw_sal.h"
29#include "rgw_sal_rados.h"
30#include "rgw_bucket.h"
31#include "rgw_multi.h"
39ae355f 32#include "rgw_acl.h"
f67539c2 33#include "rgw_acl_s3.h"
20effc67
TL
34#include "rgw_aio.h"
35#include "rgw_aio_throttle.h"
36#include "rgw_tracer.h"
f67539c2
TL
37
38#include "rgw_zone.h"
39#include "rgw_rest_conn.h"
20effc67
TL
40#include "rgw_service.h"
41#include "rgw_lc.h"
1e59de90
TL
42#include "rgw_lc_tier.h"
43#include "rgw_rest_admin.h"
44#include "rgw_rest_bucket.h"
45#include "rgw_rest_metadata.h"
46#include "rgw_rest_log.h"
47#include "rgw_rest_config.h"
48#include "rgw_rest_ratelimit.h"
49#include "rgw_rest_realm.h"
50#include "rgw_rest_user.h"
f67539c2 51#include "services/svc_sys_obj.h"
39ae355f
TL
52#include "services/svc_meta.h"
53#include "services/svc_meta_be_sobj.h"
1e59de90 54#include "services/svc_cls.h"
f67539c2
TL
55#include "services/svc_zone.h"
56#include "services/svc_tier_rados.h"
20effc67
TL
57#include "services/svc_quota.h"
58#include "services/svc_config_key.h"
59#include "services/svc_zone_utils.h"
39ae355f 60#include "services/svc_role_rados.h"
1e59de90 61#include "services/svc_user.h"
f67539c2
TL
62#include "cls/rgw/cls_rgw_client.h"
63
64#include "rgw_pubsub.h"
65
66#define dout_subsys ceph_subsys_rgw
67
20effc67
TL
68using namespace std;
69
70static string mp_ns = RGW_OBJ_NS_MULTIPART;
71
f67539c2
TL
72namespace rgw::sal {
73
20effc67
TL
74// default number of entries to list with each bucket listing call
75// (use marker to bridge between calls)
76static constexpr size_t listing_max_entries = 1000;
1e59de90 77static std::string pubsub_oid_prefix = "pubsub.";
20effc67
TL
78
79static int decode_policy(CephContext* cct,
80 bufferlist& bl,
81 RGWAccessControlPolicy* policy)
82{
83 auto iter = bl.cbegin();
84 try {
85 policy->decode(iter);
86 } catch (buffer::error& err) {
87 ldout(cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl;
88 return -EIO;
89 }
90 if (cct->_conf->subsys.should_gather<ceph_subsys_rgw, 15>()) {
91 ldout(cct, 15) << __func__ << " Read AccessControlPolicy";
92 RGWAccessControlPolicy_S3* s3policy = static_cast<RGWAccessControlPolicy_S3 *>(policy);
93 s3policy->to_xml(*_dout);
94 *_dout << dendl;
95 }
96 return 0;
97}
98
99static int rgw_op_get_bucket_policy_from_attr(const DoutPrefixProvider* dpp,
100 RadosStore* store,
101 User* user,
102 Attrs& bucket_attrs,
103 RGWAccessControlPolicy* policy,
104 optional_yield y)
105{
106 auto aiter = bucket_attrs.find(RGW_ATTR_ACL);
107
108 if (aiter != bucket_attrs.end()) {
109 int ret = decode_policy(store->ctx(), aiter->second, policy);
110 if (ret < 0)
111 return ret;
112 } else {
113 ldout(store->ctx(), 0) << "WARNING: couldn't find acl header for bucket, generating default" << dendl;
114 /* object exists, but policy is broken */
115 int r = user->load_user(dpp, y);
116 if (r < 0)
117 return r;
118
119 policy->create_default(user->get_id(), user->get_display_name());
120 }
121 return 0;
122}
123
1e59de90 124static int drain_aio(std::list<librados::AioCompletion*>& handles)
20effc67
TL
125{
126 int ret = 0;
127 while (!handles.empty()) {
128 librados::AioCompletion* handle = handles.front();
129 handles.pop_front();
130 handle->wait_for_complete();
131 int r = handle->get_return_value();
132 handle->release();
133 if (r < 0) {
134 ret = r;
135 }
136 }
137 return ret;
138}
139
1e59de90
TL
140int RadosCompletions::drain()
141{
142 return drain_aio(handles);
143}
144
20effc67
TL
145int RadosUser::list_buckets(const DoutPrefixProvider* dpp, const std::string& marker,
146 const std::string& end_marker, uint64_t max, bool need_stats,
147 BucketList &buckets, optional_yield y)
f67539c2
TL
148{
149 RGWUserBuckets ulist;
150 bool is_truncated = false;
151 int ret;
152
153 buckets.clear();
b3b6e05e 154 ret = store->ctl()->user->list_buckets(dpp, info.user_id, marker, end_marker, max,
f67539c2
TL
155 need_stats, &ulist, &is_truncated, y);
156 if (ret < 0)
157 return ret;
158
159 buckets.set_truncated(is_truncated);
160 for (const auto& ent : ulist.get_buckets()) {
20effc67 161 buckets.add(std::unique_ptr<Bucket>(new RadosBucket(this->store, ent.second, this)));
f67539c2
TL
162 }
163
164 return 0;
165}
166
20effc67
TL
167int RadosUser::create_bucket(const DoutPrefixProvider* dpp,
168 const rgw_bucket& b,
169 const std::string& zonegroup_id,
170 rgw_placement_rule& placement_rule,
171 std::string& swift_ver_location,
172 const RGWQuotaInfo * pquota_info,
173 const RGWAccessControlPolicy& policy,
174 Attrs& attrs,
175 RGWBucketInfo& info,
176 obj_version& ep_objv,
177 bool exclusive,
178 bool obj_lock_enabled,
179 bool* existed,
180 req_info& req_info,
181 std::unique_ptr<Bucket>* bucket_out,
182 optional_yield y)
183{
184 int ret;
185 bufferlist in_data;
186 RGWBucketInfo master_info;
187 rgw_bucket* pmaster_bucket;
188 uint32_t* pmaster_num_shards;
189 real_time creation_time;
190 std::unique_ptr<Bucket> bucket;
191 obj_version objv,* pobjv = NULL;
192
193 /* If it exists, look it up; otherwise create it */
194 ret = store->get_bucket(dpp, this, b, &bucket, y);
195 if (ret < 0 && ret != -ENOENT)
196 return ret;
197
198 if (ret != -ENOENT) {
199 RGWAccessControlPolicy old_policy(store->ctx());
200 *existed = true;
201 if (swift_ver_location.empty()) {
202 swift_ver_location = bucket->get_info().swift_ver_location;
203 }
204 placement_rule.inherit_from(bucket->get_info().placement_rule);
205
206 // don't allow changes to the acl policy
207 int r = rgw_op_get_bucket_policy_from_attr(dpp, store, this, bucket->get_attrs(),
208 &old_policy, y);
209 if (r >= 0 && old_policy != policy) {
210 bucket_out->swap(bucket);
211 return -EEXIST;
212 }
213 } else {
214 bucket = std::unique_ptr<Bucket>(new RadosBucket(store, b, this));
215 *existed = false;
216 bucket->set_attrs(attrs);
217 }
218
219 if (!store->svc()->zone->is_meta_master()) {
220 JSONParser jp;
221 ret = store->forward_request_to_master(dpp, this, NULL, in_data, &jp, req_info, y);
222 if (ret < 0) {
223 return ret;
224 }
225
226 JSONDecoder::decode_json("entry_point_object_ver", ep_objv, &jp);
227 JSONDecoder::decode_json("object_ver", objv, &jp);
228 JSONDecoder::decode_json("bucket_info", master_info, &jp);
229 ldpp_dout(dpp, 20) << "parsed: objv.tag=" << objv.tag << " objv.ver=" << objv.ver << dendl;
230 std::time_t ctime = ceph::real_clock::to_time_t(master_info.creation_time);
231 ldpp_dout(dpp, 20) << "got creation time: << " << std::put_time(std::localtime(&ctime), "%F %T") << dendl;
232 pmaster_bucket= &master_info.bucket;
233 creation_time = master_info.creation_time;
234 pmaster_num_shards = &master_info.layout.current_index.layout.normal.num_shards;
235 pobjv = &objv;
236 if (master_info.obj_lock_enabled()) {
237 info.flags = BUCKET_VERSIONED | BUCKET_OBJ_LOCK_ENABLED;
238 }
239 } else {
240 pmaster_bucket = NULL;
241 pmaster_num_shards = NULL;
242 if (obj_lock_enabled)
243 info.flags = BUCKET_VERSIONED | BUCKET_OBJ_LOCK_ENABLED;
244 }
245
246 std::string zid = zonegroup_id;
247 if (zid.empty()) {
248 zid = store->svc()->zone->get_zonegroup().get_id();
249 }
250
251 if (*existed) {
252 rgw_placement_rule selected_placement_rule;
253 ret = store->svc()->zone->select_bucket_placement(dpp, this->get_info(),
254 zid, placement_rule,
255 &selected_placement_rule, nullptr, y);
256 if (selected_placement_rule != info.placement_rule) {
257 ret = -EEXIST;
258 bucket_out->swap(bucket);
259 return ret;
260 }
261 } else {
262
263 ret = store->getRados()->create_bucket(this->get_info(), bucket->get_key(),
264 zid, placement_rule, swift_ver_location, pquota_info,
265 attrs, info, pobjv, &ep_objv, creation_time,
266 pmaster_bucket, pmaster_num_shards, y, dpp,
267 exclusive);
268 if (ret == -EEXIST) {
269 *existed = true;
270 /* bucket already existed, might have raced with another bucket creation,
271 * or might be partial bucket creation that never completed. Read existing
272 * bucket info, verify that the reported bucket owner is the current user.
273 * If all is ok then update the user's list of buckets. Otherwise inform
274 * client about a name conflict.
275 */
276 if (info.owner.compare(this->get_id()) != 0) {
277 return -EEXIST;
278 }
279 ret = 0;
280 } else if (ret != 0) {
281 return ret;
282 }
283 }
284
285 bucket->set_version(ep_objv);
286 bucket->get_info() = info;
287
288 RadosBucket* rbucket = static_cast<RadosBucket*>(bucket.get());
289 ret = rbucket->link(dpp, this, y, false);
290 if (ret && !*existed && ret != -EEXIST) {
291 /* if it exists (or previously existed), don't remove it! */
292 ret = rbucket->unlink(dpp, this, y);
293 if (ret < 0) {
294 ldpp_dout(dpp, 0) << "WARNING: failed to unlink bucket: ret=" << ret
295 << dendl;
296 }
297 } else if (ret == -EEXIST || (ret == 0 && *existed)) {
298 ret = -ERR_BUCKET_EXISTS;
299 }
300
301 bucket_out->swap(bucket);
302
303 return ret;
304}
305
306int RadosUser::read_attrs(const DoutPrefixProvider* dpp, optional_yield y)
307{
308 return store->ctl()->user->get_attrs_by_uid(dpp, get_id(), &attrs, y, &objv_tracker);
309}
310
311int RadosUser::merge_and_store_attrs(const DoutPrefixProvider* dpp, Attrs& new_attrs, optional_yield y)
f67539c2 312{
20effc67
TL
313 for(auto& it : new_attrs) {
314 attrs[it.first] = it.second;
315 }
316 return store_user(dpp, y, false);
317}
318
319int RadosUser::read_stats(const DoutPrefixProvider *dpp,
320 optional_yield y, RGWStorageStats* stats,
321 ceph::real_time* last_stats_sync,
322 ceph::real_time* last_stats_update)
323{
324 return store->ctl()->user->read_stats(dpp, get_id(), stats, y, last_stats_sync, last_stats_update);
325}
326
327int RadosUser::read_stats_async(const DoutPrefixProvider *dpp, RGWGetUserStats_CB* cb)
328{
1e59de90 329 return store->svc()->user->read_stats_async(dpp, get_id(), cb);
20effc67
TL
330}
331
332int RadosUser::complete_flush_stats(const DoutPrefixProvider *dpp, optional_yield y)
333{
1e59de90 334 return store->svc()->user->complete_flush_stats(dpp, get_id(), y);
20effc67
TL
335}
336
337int RadosUser::read_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch,
338 uint32_t max_entries, bool* is_truncated,
339 RGWUsageIter& usage_iter,
340 map<rgw_user_bucket, rgw_usage_log_entry>& usage)
341{
342 std::string bucket_name;
343 return store->getRados()->read_usage(dpp, get_id(), bucket_name, start_epoch,
344 end_epoch, max_entries, is_truncated,
345 usage_iter, usage);
f67539c2
TL
346}
347
20effc67
TL
348int RadosUser::trim_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch)
349{
350 std::string bucket_name;
351
352 return store->getRados()->trim_usage(dpp, get_id(), bucket_name, start_epoch, end_epoch);
353}
f67539c2 354
20effc67 355int RadosUser::load_user(const DoutPrefixProvider* dpp, optional_yield y)
f67539c2 356{
20effc67 357 return store->ctl()->user->get_info_by_uid(dpp, info.user_id, &info, y, RGWUserCtl::GetParams().set_objv_tracker(&objv_tracker).set_attrs(&attrs));
f67539c2
TL
358}
359
20effc67 360int RadosUser::store_user(const DoutPrefixProvider* dpp, optional_yield y, bool exclusive, RGWUserInfo* old_info)
f67539c2 361{
20effc67
TL
362 return store->ctl()->user->store_info(dpp, info, y,
363 RGWUserCtl::PutParams().set_objv_tracker(&objv_tracker)
364 .set_exclusive(exclusive)
365 .set_attrs(&attrs)
366 .set_old_info(old_info));
f67539c2
TL
367}
368
20effc67 369int RadosUser::remove_user(const DoutPrefixProvider* dpp, optional_yield y)
f67539c2 370{
20effc67
TL
371 return store->ctl()->user->remove_info(dpp, info, y,
372 RGWUserCtl::RemoveParams().set_objv_tracker(&objv_tracker));
f67539c2
TL
373}
374
1e59de90
TL
375int RadosUser::verify_mfa(const std::string& mfa_str, bool* verified,
376 const DoutPrefixProvider* dpp, optional_yield y)
377{
378 vector<string> params;
379 get_str_vec(mfa_str, " ", params);
380
381 if (params.size() != 2) {
382 ldpp_dout(dpp, 5) << "NOTICE: invalid mfa string provided: " << mfa_str << dendl;
383 return -EINVAL;
384 }
385
386 string& serial = params[0];
387 string& pin = params[1];
388
389 auto i = info.mfa_ids.find(serial);
390 if (i == info.mfa_ids.end()) {
391 ldpp_dout(dpp, 5) << "NOTICE: user does not have mfa device with serial=" << serial << dendl;
392 return -EACCES;
393 }
394
395 int ret = store->svc()->cls->mfa.check_mfa(dpp, info.user_id, serial, pin, y);
396 if (ret < 0) {
397 ldpp_dout(dpp, 20) << "NOTICE: failed to check MFA, serial=" << serial << dendl;
398 return -EACCES;
399 }
400
401 *verified = true;
402
403 return 0;
404}
405
20effc67
TL
406RadosBucket::~RadosBucket() {}
407
408int RadosBucket::remove_bucket(const DoutPrefixProvider* dpp,
b3b6e05e 409 bool delete_children,
b3b6e05e 410 bool forward_to_master,
20effc67
TL
411 req_info* req_info,
412 optional_yield y)
f67539c2
TL
413{
414 int ret;
415
416 // Refresh info
20effc67
TL
417 ret = load_bucket(dpp, y);
418 if (ret < 0) {
f67539c2 419 return ret;
20effc67 420 }
f67539c2
TL
421
422 ListParams params;
423 params.list_versions = true;
424 params.allow_unordered = true;
425
426 ListResults results;
427
f67539c2
TL
428 do {
429 results.objs.clear();
430
b3b6e05e 431 ret = list(dpp, params, 1000, results, y);
20effc67 432 if (ret < 0) {
b3b6e05e 433 return ret;
20effc67 434 }
f67539c2
TL
435
436 if (!results.objs.empty() && !delete_children) {
b3b6e05e 437 ldpp_dout(dpp, -1) << "ERROR: could not remove non-empty bucket " << info.bucket.name <<
f67539c2
TL
438 dendl;
439 return -ENOTEMPTY;
440 }
441
442 for (const auto& obj : results.objs) {
443 rgw_obj_key key(obj.key);
444 /* xxx dang */
20effc67 445 ret = rgw_remove_object(dpp, store, this, key);
f67539c2
TL
446 if (ret < 0 && ret != -ENOENT) {
447 return ret;
448 }
449 }
b3b6e05e 450 } while(results.is_truncated);
f67539c2 451
20effc67 452 ret = abort_multiparts(dpp, store->ctx());
a4b75251
TL
453 if (ret < 0) {
454 return ret;
f67539c2
TL
455 }
456
20effc67
TL
457 // remove lifecycle config, if any (XXX note could be made generic)
458 (void) store->getRados()->get_lc()->remove_bucket_config(
459 this, get_attrs());
460
461 ret = store->ctl()->bucket->sync_user_stats(dpp, info.owner, info, y, nullptr);
f67539c2
TL
462 if (ret < 0) {
463 ldout(store->ctx(), 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
464 }
465
466 RGWObjVersionTracker ot;
467
468 // if we deleted children above we will force delete, as any that
469 // remain is detrius from a prior bug
b3b6e05e 470 ret = store->getRados()->delete_bucket(info, ot, y, dpp, !delete_children);
f67539c2 471 if (ret < 0) {
b3b6e05e 472 ldpp_dout(dpp, -1) << "ERROR: could not remove bucket " <<
f67539c2
TL
473 info.bucket.name << dendl;
474 return ret;
475 }
476
477 // if bucket has notification definitions associated with it
478 // they should be removed (note that any pending notifications on the bucket are still going to be sent)
1e59de90
TL
479 const RGWPubSub ps(store, info.owner.tenant);
480 const RGWPubSub::Bucket ps_bucket(ps, this);
b3b6e05e 481 const auto ps_ret = ps_bucket.remove_notifications(dpp, y);
f67539c2 482 if (ps_ret < 0 && ps_ret != -ENOENT) {
20effc67 483 ldpp_dout(dpp, -1) << "ERROR: unable to remove notifications from bucket. ret=" << ps_ret << dendl;
f67539c2
TL
484 }
485
b3b6e05e 486 ret = store->ctl()->bucket->unlink_bucket(info.owner, info.bucket, y, dpp, false);
f67539c2 487 if (ret < 0) {
b3b6e05e 488 ldpp_dout(dpp, -1) << "ERROR: unable to remove user bucket information" << dendl;
f67539c2
TL
489 }
490
491 if (forward_to_master) {
492 bufferlist in_data;
b3b6e05e 493 ret = store->forward_request_to_master(dpp, owner, &ot.read_version, in_data, nullptr, *req_info, y);
f67539c2
TL
494 if (ret < 0) {
495 if (ret == -ENOENT) {
496 /* adjust error, we want to return with NoSuchBucket and not
497 * NoSuchKey */
498 ret = -ERR_NO_SUCH_BUCKET;
499 }
500 return ret;
501 }
502 }
503
504 return ret;
505}
506
20effc67
TL
507int RadosBucket::remove_bucket_bypass_gc(int concurrent_max, bool
508 keep_index_consistent,
509 optional_yield y, const
510 DoutPrefixProvider *dpp)
511{
512 int ret;
513 map<RGWObjCategory, RGWStorageStats> stats;
514 map<string, bool> common_prefixes;
515 RGWObjectCtx obj_ctx(store);
516 CephContext *cct = store->ctx();
517
518 string bucket_ver, master_ver;
519
1e59de90 520 ret = load_bucket(dpp, y);
20effc67
TL
521 if (ret < 0)
522 return ret;
523
1e59de90
TL
524 const auto& index = info.get_current_index();
525 ret = read_stats(dpp, index, RGW_NO_SHARD, &bucket_ver, &master_ver, stats, NULL);
20effc67
TL
526 if (ret < 0)
527 return ret;
528
529 ret = abort_multiparts(dpp, cct);
530 if (ret < 0) {
531 return ret;
532 }
533
534 rgw::sal::Bucket::ListParams params;
535 rgw::sal::Bucket::ListResults results;
536
537 params.list_versions = true;
538 params.allow_unordered = true;
539
1e59de90 540 std::list<librados::AioCompletion*> handles;
20effc67
TL
541
542 int max_aio = concurrent_max;
543 results.is_truncated = true;
544
545 while (results.is_truncated) {
1e59de90 546 ret = list(dpp, params, listing_max_entries, results, y);
20effc67
TL
547 if (ret < 0)
548 return ret;
549
550 std::vector<rgw_bucket_dir_entry>::iterator it = results.objs.begin();
551 for (; it != results.objs.end(); ++it) {
552 RGWObjState *astate = NULL;
1e59de90
TL
553 RGWObjManifest *amanifest = nullptr;
554 rgw_obj obj{get_key(), it->key};
20effc67 555
1e59de90
TL
556 ret = store->getRados()->get_obj_state(dpp, &obj_ctx, get_info(),
557 obj, &astate, &amanifest,
558 false, y);
20effc67
TL
559 if (ret == -ENOENT) {
560 ldpp_dout(dpp, 1) << "WARNING: cannot find obj state for obj " << obj << dendl;
561 continue;
562 }
563 if (ret < 0) {
564 ldpp_dout(dpp, -1) << "ERROR: get obj state returned with error " << ret << dendl;
565 return ret;
566 }
567
1e59de90
TL
568 if (amanifest) {
569 RGWObjManifest& manifest = *amanifest;
20effc67 570 RGWObjManifest::obj_iterator miter = manifest.obj_begin(dpp);
1e59de90 571 const rgw_obj head_obj = manifest.get_obj();
20effc67 572 rgw_raw_obj raw_head_obj;
1e59de90 573 store->get_raw_obj(manifest.get_head_placement_rule(), head_obj, &raw_head_obj);
20effc67
TL
574
575 for (; miter != manifest.obj_end(dpp) && max_aio--; ++miter) {
576 if (!max_aio) {
1e59de90 577 ret = drain_aio(handles);
20effc67
TL
578 if (ret < 0) {
579 ldpp_dout(dpp, -1) << "ERROR: could not drain handles as aio completion returned with " << ret << dendl;
580 return ret;
581 }
582 max_aio = concurrent_max;
583 }
584
1e59de90 585 rgw_raw_obj last_obj = miter.get_location().get_raw_obj(store->getRados());
20effc67
TL
586 if (last_obj == raw_head_obj) {
587 // have the head obj deleted at the end
588 continue;
589 }
590
1e59de90 591 ret = store->getRados()->delete_raw_obj_aio(dpp, last_obj, handles);
20effc67
TL
592 if (ret < 0) {
593 ldpp_dout(dpp, -1) << "ERROR: delete obj aio failed with " << ret << dendl;
594 return ret;
595 }
596 } // for all shadow objs
597
1e59de90
TL
598 ret = store->getRados()->delete_obj_aio(dpp, head_obj, get_info(), astate,
599 handles, keep_index_consistent, y);
20effc67
TL
600 if (ret < 0) {
601 ldpp_dout(dpp, -1) << "ERROR: delete obj aio failed with " << ret << dendl;
602 return ret;
603 }
604 }
605
606 if (!max_aio) {
1e59de90 607 ret = drain_aio(handles);
20effc67
TL
608 if (ret < 0) {
609 ldpp_dout(dpp, -1) << "ERROR: could not drain handles as aio completion returned with " << ret << dendl;
610 return ret;
611 }
612 max_aio = concurrent_max;
613 }
1e59de90 614 obj_ctx.invalidate(obj);
20effc67
TL
615 } // for all RGW objects in results
616 } // while is_truncated
617
1e59de90 618 ret = drain_aio(handles);
20effc67
TL
619 if (ret < 0) {
620 ldpp_dout(dpp, -1) << "ERROR: could not drain handles as aio completion returned with " << ret << dendl;
621 return ret;
622 }
623
624 sync_user_stats(dpp, y);
625 if (ret < 0) {
626 ldpp_dout(dpp, 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
627 }
628
629 RGWObjVersionTracker objv_tracker;
630
631 // this function can only be run if caller wanted children to be
632 // deleted, so we can ignore the check for children as any that
633 // remain are detritus from a prior bug
634 ret = remove_bucket(dpp, true, false, nullptr, y);
635 if (ret < 0) {
636 ldpp_dout(dpp, -1) << "ERROR: could not remove bucket " << this << dendl;
637 return ret;
638 }
639
640 return ret;
641}
642
643int RadosBucket::load_bucket(const DoutPrefixProvider* dpp, optional_yield y, bool get_stats)
f67539c2 644{
20effc67
TL
645 int ret;
646
1e59de90 647 RGWSI_MetaBackend_CtxParams bectx_params = RGWSI_MetaBackend_CtxParams_SObj();
f67539c2 648 RGWObjVersionTracker ep_ot;
20effc67
TL
649 if (info.bucket.bucket_id.empty()) {
650 ret = store->ctl()->bucket->read_bucket_info(info.bucket, &info, y, dpp,
f67539c2
TL
651 RGWBucketCtl::BucketInstance::GetParams()
652 .set_mtime(&mtime)
653 .set_attrs(&attrs)
654 .set_bectx_params(bectx_params),
655 &ep_ot);
20effc67
TL
656 } else {
657 ret = store->ctl()->bucket->read_bucket_instance_info(info.bucket, &info, y, dpp,
658 RGWBucketCtl::BucketInstance::GetParams()
659 .set_mtime(&mtime)
660 .set_attrs(&attrs)
661 .set_bectx_params(bectx_params));
662 }
663 if (ret != 0) {
664 return ret;
f67539c2 665 }
f67539c2 666
20effc67 667 bucket_version = ep_ot.read_version;
f67539c2 668
20effc67
TL
669 if (get_stats) {
670 ret = store->ctl()->bucket->read_bucket_stats(info.bucket, &ent, y, dpp);
f67539c2
TL
671 }
672
20effc67 673 return ret;
f67539c2
TL
674}
675
1e59de90
TL
676int RadosBucket::read_stats(const DoutPrefixProvider *dpp,
677 const bucket_index_layout_generation& idx_layout,
678 int shard_id, std::string* bucket_ver, std::string* master_ver,
679 std::map<RGWObjCategory, RGWStorageStats>& stats,
680 std::string* max_marker, bool* syncstopped)
f67539c2 681{
1e59de90 682 return store->getRados()->get_bucket_stats(dpp, info, idx_layout, shard_id, bucket_ver, master_ver, stats, max_marker, syncstopped);
f67539c2
TL
683}
684
1e59de90
TL
685int RadosBucket::read_stats_async(const DoutPrefixProvider *dpp,
686 const bucket_index_layout_generation& idx_layout,
687 int shard_id, RGWGetBucketStats_CB* ctx)
f67539c2 688{
1e59de90 689 return store->getRados()->get_bucket_stats_async(dpp, get_info(), idx_layout, shard_id, ctx);
f67539c2
TL
690}
691
20effc67 692int RadosBucket::sync_user_stats(const DoutPrefixProvider *dpp, optional_yield y)
f67539c2 693{
20effc67 694 return store->ctl()->bucket->sync_user_stats(dpp, owner->get_id(), info, y, &ent);
f67539c2
TL
695}
696
20effc67 697int RadosBucket::update_container_stats(const DoutPrefixProvider* dpp)
f67539c2
TL
698{
699 int ret;
700 map<std::string, RGWBucketEnt> m;
701
702 m[info.bucket.name] = ent;
b3b6e05e 703 ret = store->getRados()->update_containers_stats(m, dpp);
f67539c2
TL
704 if (!ret)
705 return -EEXIST;
706 if (ret < 0)
707 return ret;
708
20effc67 709 map<std::string, RGWBucketEnt>::iterator iter = m.find(info.bucket.name);
f67539c2
TL
710 if (iter == m.end())
711 return -EINVAL;
712
713 ent.count = iter->second.count;
714 ent.size = iter->second.size;
715 ent.size_rounded = iter->second.size_rounded;
716 ent.creation_time = iter->second.creation_time;
717 ent.placement_rule = std::move(iter->second.placement_rule);
718
719 info.creation_time = ent.creation_time;
720 info.placement_rule = ent.placement_rule;
721
722 return 0;
723}
724
20effc67 725int RadosBucket::check_bucket_shards(const DoutPrefixProvider* dpp)
f67539c2 726{
b3b6e05e 727 return store->getRados()->check_bucket_shards(info, info.bucket, get_count(), dpp);
f67539c2
TL
728}
729
20effc67 730int RadosBucket::link(const DoutPrefixProvider* dpp, User* new_user, optional_yield y, bool update_entrypoint, RGWObjVersionTracker* objv)
f67539c2
TL
731{
732 RGWBucketEntryPoint ep;
733 ep.bucket = info.bucket;
20effc67 734 ep.owner = new_user->get_id();
f67539c2
TL
735 ep.creation_time = get_creation_time();
736 ep.linked = true;
20effc67 737 Attrs ep_attrs;
f67539c2
TL
738 rgw_ep_info ep_data{ep, ep_attrs};
739
20effc67
TL
740 int r = store->ctl()->bucket->link_bucket(new_user->get_id(), info.bucket,
741 get_creation_time(), y, dpp, update_entrypoint,
742 &ep_data);
743 if (r < 0)
744 return r;
745
746 if (objv)
747 *objv = ep_data.ep_objv;
748
749 return r;
f67539c2
TL
750}
751
20effc67 752int RadosBucket::unlink(const DoutPrefixProvider* dpp, User* new_user, optional_yield y, bool update_entrypoint)
f67539c2 753{
20effc67 754 return store->ctl()->bucket->unlink_bucket(new_user->get_id(), info.bucket, y, dpp, update_entrypoint);
f67539c2
TL
755}
756
39ae355f 757int RadosBucket::chown(const DoutPrefixProvider* dpp, User& new_user, optional_yield y)
f67539c2 758{
20effc67 759 std::string obj_marker;
39ae355f 760 int r;
20effc67 761
39ae355f
TL
762 if (!owner) {
763 ldpp_dout(dpp, 0) << __func__ << " Cannot chown without an owner " << dendl;
764 return -EINVAL;
765 }
20effc67 766
39ae355f 767 r = this->unlink(dpp, owner, y);
20effc67
TL
768 if (r < 0) {
769 return r;
770 }
f67539c2 771
39ae355f 772 return this->link(dpp, &new_user, y);
f67539c2
TL
773}
774
20effc67 775int RadosBucket::put_info(const DoutPrefixProvider* dpp, bool exclusive, ceph::real_time _mtime)
f67539c2
TL
776{
777 mtime = _mtime;
1e59de90 778 return store->getRados()->put_bucket_instance_info(info, exclusive, mtime, &attrs, dpp, null_yield);
f67539c2
TL
779}
780
781/* Make sure to call get_bucket_info() if you need it first */
20effc67 782bool RadosBucket::is_owner(User* user)
f67539c2 783{
20effc67 784 return (info.owner.compare(user->get_id()) == 0);
f67539c2
TL
785}
786
20effc67 787int RadosBucket::check_empty(const DoutPrefixProvider* dpp, optional_yield y)
f67539c2 788{
b3b6e05e 789 return store->getRados()->check_bucket_empty(dpp, info, y);
f67539c2
TL
790}
791
1e59de90 792int RadosBucket::check_quota(const DoutPrefixProvider *dpp, RGWQuota& quota, uint64_t obj_size,
f67539c2
TL
793 optional_yield y, bool check_size_only)
794{
1e59de90
TL
795 return store->getRados()->check_quota(dpp, info.owner, get_key(),
796 quota, obj_size, y, check_size_only);
f67539c2
TL
797}
798
20effc67 799int RadosBucket::merge_and_store_attrs(const DoutPrefixProvider* dpp, Attrs& new_attrs, optional_yield y)
f67539c2 800{
20effc67
TL
801 for(auto& it : new_attrs) {
802 attrs[it.first] = it.second;
803 }
804 return store->ctl()->bucket->set_bucket_instance_attrs(get_info(),
805 new_attrs, &get_info().objv_tracker, y, dpp);
f67539c2
TL
806}
807
20effc67 808int RadosBucket::try_refresh_info(const DoutPrefixProvider* dpp, ceph::real_time* pmtime)
f67539c2 809{
b3b6e05e 810 return store->getRados()->try_refresh_bucket_info(info, pmtime, dpp, &attrs);
f67539c2
TL
811}
812
20effc67
TL
813int RadosBucket::read_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch,
814 uint32_t max_entries, bool* is_truncated,
f67539c2
TL
815 RGWUsageIter& usage_iter,
816 map<rgw_user_bucket, rgw_usage_log_entry>& usage)
817{
20effc67
TL
818 return store->getRados()->read_usage(dpp, owner->get_id(), get_name(), start_epoch,
819 end_epoch, max_entries, is_truncated,
820 usage_iter, usage);
f67539c2
TL
821}
822
20effc67 823int RadosBucket::trim_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch)
f67539c2 824{
20effc67
TL
825 return store->getRados()->trim_usage(dpp, owner->get_id(), get_name(), start_epoch, end_epoch);
826}
f67539c2 827
20effc67
TL
828int RadosBucket::remove_objs_from_index(const DoutPrefixProvider *dpp, std::list<rgw_obj_index_key>& objs_to_unlink)
829{
830 return store->getRados()->remove_objs_from_index(dpp, info, objs_to_unlink);
831}
f67539c2 832
20effc67
TL
833int RadosBucket::check_index(const DoutPrefixProvider *dpp, std::map<RGWObjCategory, RGWStorageStats>& existing_stats, std::map<RGWObjCategory, RGWStorageStats>& calculated_stats)
834{
835 return store->getRados()->bucket_check_index(dpp, info, &existing_stats, &calculated_stats);
f67539c2
TL
836}
837
20effc67 838int RadosBucket::rebuild_index(const DoutPrefixProvider *dpp)
f67539c2 839{
20effc67 840 return store->getRados()->bucket_rebuild_index(dpp, info);
f67539c2
TL
841}
842
20effc67 843int RadosBucket::set_tag_timeout(const DoutPrefixProvider *dpp, uint64_t timeout)
f67539c2 844{
20effc67
TL
845 return store->getRados()->cls_obj_set_bucket_tag_timeout(dpp, info, timeout);
846}
f67539c2 847
20effc67
TL
848int RadosBucket::purge_instance(const DoutPrefixProvider* dpp)
849{
850 int max_shards = (info.layout.current_index.layout.normal.num_shards > 0 ? info.layout.current_index.layout.normal.num_shards : 1);
851 for (int i = 0; i < max_shards; i++) {
852 RGWRados::BucketShard bs(store->getRados());
853 int shard_id = (info.layout.current_index.layout.normal.num_shards > 0 ? i : -1);
1e59de90 854 int ret = bs.init(dpp, info, info.layout.current_index, shard_id);
20effc67
TL
855 if (ret < 0) {
856 cerr << "ERROR: bs.init(bucket=" << info.bucket << ", shard=" << shard_id
857 << "): " << cpp_strerror(-ret) << std::endl;
858 return ret;
859 }
860 ret = store->getRados()->bi_remove(dpp, bs);
861 if (ret < 0) {
862 cerr << "ERROR: failed to remove bucket index object: "
863 << cpp_strerror(-ret) << std::endl;
864 return ret;
865 }
866 }
867 return 0;
868}
869
870int RadosBucket::set_acl(const DoutPrefixProvider* dpp, RGWAccessControlPolicy &acl, optional_yield y)
871{
872 bufferlist aclbl;
873
874 acls = acl;
875 acl.encode(aclbl);
876 map<string, bufferlist>& attrs = get_attrs();
877
878 attrs[RGW_ATTR_ACL] = aclbl;
879 info.owner = acl.get_owner().get_id();
880
881 int r = store->ctl()->bucket->store_bucket_instance_info(info.bucket,
882 info, y, dpp,
883 RGWBucketCtl::BucketInstance::PutParams().set_attrs(&attrs));
884 if (r < 0) {
885 cerr << "ERROR: failed to set bucket owner: " << cpp_strerror(-r) << std::endl;
886 return r;
887 }
888
889 return 0;
890}
891
892std::unique_ptr<Object> RadosBucket::get_object(const rgw_obj_key& k)
893{
894 return std::make_unique<RadosObject>(this->store, k, this);
895}
896
897int RadosBucket::list(const DoutPrefixProvider* dpp, ListParams& params, int max, ListResults& results, optional_yield y)
898{
899 RGWRados::Bucket target(store->getRados(), get_info());
900 if (params.shard_id >= 0) {
901 target.set_shard_id(params.shard_id);
902 }
903 RGWRados::Bucket::List list_op(&target);
904
905 list_op.params.prefix = params.prefix;
f67539c2
TL
906 list_op.params.delim = params.delim;
907 list_op.params.marker = params.marker;
908 list_op.params.ns = params.ns;
909 list_op.params.end_marker = params.end_marker;
20effc67
TL
910 list_op.params.ns = params.ns;
911 list_op.params.enforce_ns = params.enforce_ns;
912 list_op.params.access_list_filter = params.access_list_filter;
913 list_op.params.force_check_filter = params.force_check_filter;
f67539c2
TL
914 list_op.params.list_versions = params.list_versions;
915 list_op.params.allow_unordered = params.allow_unordered;
916
b3b6e05e 917 int ret = list_op.list_objects(dpp, max, &results.objs, &results.common_prefixes, &results.is_truncated, y);
f67539c2
TL
918 if (ret >= 0) {
919 results.next_marker = list_op.get_next_marker();
522d829b 920 params.marker = results.next_marker;
f67539c2
TL
921 }
922
923 return ret;
924}
925
20effc67
TL
926std::unique_ptr<MultipartUpload> RadosBucket::get_multipart_upload(
927 const std::string& oid,
928 std::optional<std::string> upload_id,
929 ACLOwner owner, ceph::real_time mtime)
f67539c2 930{
20effc67
TL
931 return std::make_unique<RadosMultipartUpload>(this->store, this, oid, upload_id,
932 std::move(owner), mtime);
f67539c2
TL
933}
934
20effc67
TL
935int RadosBucket::list_multiparts(const DoutPrefixProvider *dpp,
936 const string& prefix,
937 string& marker,
938 const string& delim,
939 const int& max_uploads,
940 vector<std::unique_ptr<MultipartUpload>>& uploads,
941 map<string, bool> *common_prefixes,
942 bool *is_truncated)
f67539c2 943{
20effc67
TL
944 rgw::sal::Bucket::ListParams params;
945 rgw::sal::Bucket::ListResults results;
946 MultipartMetaFilter mp_filter;
f67539c2 947
20effc67
TL
948 params.prefix = prefix;
949 params.delim = delim;
950 params.marker = marker;
951 params.ns = RGW_OBJ_NS_MULTIPART;
952 params.access_list_filter = &mp_filter;
f67539c2 953
20effc67
TL
954 int ret = list(dpp, params, max_uploads, results, null_yield);
955
956 if (ret < 0)
957 return ret;
958
959 if (!results.objs.empty()) {
960 for (const rgw_bucket_dir_entry& dentry : results.objs) {
961 rgw_obj_key key(dentry.key);
962 ACLOwner owner(rgw_user(dentry.meta.owner));
963 owner.set_name(dentry.meta.owner_display_name);
964 uploads.push_back(this->get_multipart_upload(key.name,
1e59de90 965 std::nullopt, std::move(owner), dentry.meta.mtime));
f67539c2
TL
966 }
967 }
20effc67
TL
968 if (common_prefixes) {
969 *common_prefixes = std::move(results.common_prefixes);
970 }
971 *is_truncated = results.is_truncated;
972 marker = params.marker.name;
973
f67539c2
TL
974 return 0;
975}
976
20effc67
TL
977int RadosBucket::abort_multiparts(const DoutPrefixProvider* dpp,
978 CephContext* cct)
f67539c2 979{
20effc67
TL
980 constexpr int max = 1000;
981 int ret, num_deleted = 0;
982 vector<std::unique_ptr<MultipartUpload>> uploads;
20effc67
TL
983 string marker;
984 bool is_truncated;
f67539c2 985
20effc67
TL
986 const std::string empty_delim;
987 const std::string empty_prefix;
f67539c2 988
20effc67
TL
989 do {
990 ret = list_multiparts(dpp, empty_prefix, marker, empty_delim,
991 max, uploads, nullptr, &is_truncated);
992 if (ret < 0) {
993 ldpp_dout(dpp, 0) << __func__ <<
994 " ERROR : calling list_bucket_multiparts; ret=" << ret <<
995 "; bucket=\"" << this << "\"" << dendl;
996 return ret;
997 }
998 ldpp_dout(dpp, 20) << __func__ <<
999 " INFO: aborting and cleaning up multipart upload(s); bucket=\"" <<
1000 this << "\"; uploads.size()=" << uploads.size() <<
1001 "; is_truncated=" << is_truncated << dendl;
1002
1003 if (!uploads.empty()) {
1004 for (const auto& upload : uploads) {
1e59de90 1005 ret = upload->abort(dpp, cct);
20effc67
TL
1006 if (ret < 0) {
1007 // we're doing a best-effort; if something cannot be found,
1008 // log it and keep moving forward
1009 if (ret != -ENOENT && ret != -ERR_NO_SUCH_UPLOAD) {
1010 ldpp_dout(dpp, 0) << __func__ <<
1011 " ERROR : failed to abort and clean-up multipart upload \"" <<
1012 upload->get_meta() << "\"" << dendl;
1013 return ret;
1014 } else {
1015 ldpp_dout(dpp, 10) << __func__ <<
1016 " NOTE : unable to find part(s) of "
1017 "aborted multipart upload of \"" << upload->get_meta() <<
1018 "\" for cleaning up" << dendl;
1019 }
1020 }
1021 num_deleted++;
1022 }
1023 if (num_deleted) {
1024 ldpp_dout(dpp, 0) << __func__ <<
1025 " WARNING : aborted " << num_deleted <<
1026 " incomplete multipart uploads" << dendl;
1027 }
1028 }
1029 } while (is_truncated);
f67539c2 1030
20effc67 1031 return 0;
f67539c2
TL
1032}
1033
1e59de90
TL
1034std::string RadosBucket::topics_oid() const {
1035 return pubsub_oid_prefix + get_tenant() + ".bucket." + get_name() + "/" + get_marker();
1036}
1037
1038int RadosBucket::read_topics(rgw_pubsub_bucket_topics& notifications,
1039 RGWObjVersionTracker* objv_tracker, optional_yield y, const DoutPrefixProvider *dpp)
1040{
1041 bufferlist bl;
1042 const int ret = rgw_get_system_obj(store->svc()->sysobj,
1043 store->svc()->zone->get_zone_params().log_pool,
1044 topics_oid(),
1045 bl,
1046 objv_tracker,
1047 nullptr, y, dpp, nullptr);
1048 if (ret < 0) {
1049 return ret;
1050 }
1051
1052 auto iter = bl.cbegin();
1053 try {
1054 decode(notifications, iter);
1055 } catch (buffer::error& err) {
1056 ldpp_dout(dpp, 20) << " failed to decode bucket notifications from oid: " << topics_oid() << ". for bucket: "
1057 << get_name() << ". error: " << err.what() << dendl;
1058 return -EIO;
1059 }
1060
1061 return 0;
1062}
1063
1064int RadosBucket::write_topics(const rgw_pubsub_bucket_topics& notifications,
1065 RGWObjVersionTracker* objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) {
1066 bufferlist bl;
1067 encode(notifications, bl);
1068
1069 return rgw_put_system_obj(dpp, store->svc()->sysobj,
1070 store->svc()->zone->get_zone_params().log_pool,
1071 topics_oid(),
1072 bl, false, objv_tracker, real_time(), y);
1073}
1074
1075int RadosBucket::remove_topics(RGWObjVersionTracker* objv_tracker,
1076 optional_yield y, const DoutPrefixProvider *dpp) {
1077 return rgw_delete_system_obj(dpp, store->svc()->sysobj,
1078 store->svc()->zone->get_zone_params().log_pool,
1079 topics_oid(),
1080 objv_tracker, y);
1081}
1082
20effc67 1083std::unique_ptr<User> RadosStore::get_user(const rgw_user &u)
f67539c2 1084{
20effc67 1085 return std::make_unique<RadosUser>(this, u);
f67539c2
TL
1086}
1087
20effc67 1088std::string RadosStore::get_cluster_id(const DoutPrefixProvider* dpp, optional_yield y)
f67539c2 1089{
20effc67 1090 return getRados()->get_cluster_fsid(dpp, y);
f67539c2
TL
1091}
1092
20effc67 1093int RadosStore::get_user_by_access_key(const DoutPrefixProvider* dpp, const std::string& key, optional_yield y, std::unique_ptr<User>* user)
f67539c2 1094{
20effc67
TL
1095 RGWUserInfo uinfo;
1096 User* u;
1097 RGWObjVersionTracker objv_tracker;
1098
1099 int r = ctl()->user->get_info_by_access_key(dpp, key, &uinfo, y, RGWUserCtl::GetParams().set_objv_tracker(&objv_tracker));
1100 if (r < 0)
f67539c2 1101 return r;
f67539c2 1102
20effc67
TL
1103 u = new RadosUser(this, uinfo);
1104 if (!u)
1105 return -ENOMEM;
f67539c2 1106
20effc67
TL
1107 u->get_version_tracker() = objv_tracker;
1108
1109 user->reset(u);
1110 return 0;
f67539c2
TL
1111}
1112
20effc67 1113int RadosStore::get_user_by_email(const DoutPrefixProvider* dpp, const std::string& email, optional_yield y, std::unique_ptr<User>* user)
f67539c2 1114{
20effc67
TL
1115 RGWUserInfo uinfo;
1116 User* u;
1117 RGWObjVersionTracker objv_tracker;
f67539c2 1118
20effc67
TL
1119 int r = ctl()->user->get_info_by_email(dpp, email, &uinfo, y, RGWUserCtl::GetParams().set_objv_tracker(&objv_tracker));
1120 if (r < 0)
1121 return r;
f67539c2 1122
20effc67
TL
1123 u = new RadosUser(this, uinfo);
1124 if (!u)
1125 return -ENOMEM;
f67539c2 1126
20effc67 1127 u->get_version_tracker() = objv_tracker;
f67539c2 1128
20effc67
TL
1129 user->reset(u);
1130 return 0;
f67539c2
TL
1131}
1132
20effc67 1133int RadosStore::get_user_by_swift(const DoutPrefixProvider* dpp, const std::string& user_str, optional_yield y, std::unique_ptr<User>* user)
f67539c2 1134{
20effc67
TL
1135 RGWUserInfo uinfo;
1136 User* u;
1137 RGWObjVersionTracker objv_tracker;
f67539c2 1138
20effc67
TL
1139 int r = ctl()->user->get_info_by_swift(dpp, user_str, &uinfo, y, RGWUserCtl::GetParams().set_objv_tracker(&objv_tracker));
1140 if (r < 0)
1141 return r;
f67539c2 1142
20effc67
TL
1143 u = new RadosUser(this, uinfo);
1144 if (!u)
1145 return -ENOMEM;
f67539c2 1146
20effc67 1147 u->get_version_tracker() = objv_tracker;
f67539c2 1148
20effc67
TL
1149 user->reset(u);
1150 return 0;
f67539c2
TL
1151}
1152
20effc67 1153std::unique_ptr<Object> RadosStore::get_object(const rgw_obj_key& k)
f67539c2 1154{
20effc67 1155 return std::make_unique<RadosObject>(this, k);
f67539c2
TL
1156}
1157
20effc67 1158int RadosStore::get_bucket(const DoutPrefixProvider* dpp, User* u, const rgw_bucket& b, std::unique_ptr<Bucket>* bucket, optional_yield y)
f67539c2
TL
1159{
1160 int ret;
20effc67 1161 Bucket* bp;
f67539c2 1162
20effc67
TL
1163 bp = new RadosBucket(this, b, u);
1164 ret = bp->load_bucket(dpp, y);
f67539c2 1165 if (ret < 0) {
20effc67 1166 delete bp;
f67539c2
TL
1167 return ret;
1168 }
1169
20effc67
TL
1170 bucket->reset(bp);
1171 return 0;
f67539c2
TL
1172}
1173
20effc67 1174int RadosStore::get_bucket(User* u, const RGWBucketInfo& i, std::unique_ptr<Bucket>* bucket)
f67539c2 1175{
20effc67 1176 Bucket* bp;
f67539c2 1177
20effc67
TL
1178 bp = new RadosBucket(this, i, u);
1179 /* Don't need to fetch the bucket info, use the provided one */
f67539c2 1180
20effc67
TL
1181 bucket->reset(bp);
1182 return 0;
f67539c2
TL
1183}
1184
20effc67 1185int RadosStore::get_bucket(const DoutPrefixProvider* dpp, User* u, const std::string& tenant, const std::string& name, std::unique_ptr<Bucket>* bucket, optional_yield y)
f67539c2 1186{
20effc67 1187 rgw_bucket b;
f67539c2 1188
20effc67
TL
1189 b.tenant = tenant;
1190 b.name = name;
f67539c2 1191
20effc67 1192 return get_bucket(dpp, u, b, bucket, y);
f67539c2
TL
1193}
1194
20effc67 1195bool RadosStore::is_meta_master()
f67539c2 1196{
20effc67 1197 return svc()->zone->is_meta_master();
f67539c2
TL
1198}
1199
20effc67
TL
1200int RadosStore::forward_request_to_master(const DoutPrefixProvider *dpp, User* user, obj_version* objv,
1201 bufferlist& in_data,
1202 JSONParser* jp, req_info& info,
1203 optional_yield y)
f67539c2 1204{
20effc67
TL
1205 if (is_meta_master()) {
1206 /* We're master, don't forward */
1207 return 0;
1208 }
f67539c2 1209
20effc67
TL
1210 if (!svc()->zone->get_master_conn()) {
1211 ldpp_dout(dpp, 0) << "rest connection is invalid" << dendl;
1212 return -EINVAL;
f67539c2 1213 }
20effc67
TL
1214 ldpp_dout(dpp, 0) << "sending request to master zonegroup" << dendl;
1215 bufferlist response;
1216 std::string uid_str = user->get_id().to_str();
1217#define MAX_REST_RESPONSE (128 * 1024) // we expect a very small response
1218 int ret = svc()->zone->get_master_conn()->forward(dpp, rgw_user(uid_str), info,
1219 objv, MAX_REST_RESPONSE,
1220 &in_data, &response, y);
1221 if (ret < 0)
1222 return ret;
1223
1224 ldpp_dout(dpp, 20) << "response: " << response.c_str() << dendl;
1225 if (jp && !jp->parse(response.c_str(), response.length())) {
1226 ldpp_dout(dpp, 0) << "failed parsing response from master zonegroup" << dendl;
1227 return -EINVAL;
f67539c2
TL
1228 }
1229
20effc67 1230 return 0;
f67539c2
TL
1231}
1232
39ae355f
TL
1233int RadosStore::forward_iam_request_to_master(const DoutPrefixProvider *dpp, const RGWAccessKey& key, obj_version* objv,
1234 bufferlist& in_data,
1235 RGWXMLDecoder::XMLParser* parser, req_info& info,
1236 optional_yield y)
1237{
1238 if (is_meta_master()) {
1239 /* We're master, don't forward */
1240 return 0;
1241 }
1242
1243 if (!svc()->zone->get_master_conn()) {
1244 ldpp_dout(dpp, 0) << "rest connection is invalid" << dendl;
1245 return -EINVAL;
1246 }
1247 ldpp_dout(dpp, 0) << "sending request to master zonegroup" << dendl;
1248 bufferlist response;
1249#define MAX_REST_RESPONSE (128 * 1024) // we expect a very small response
1250 int ret = svc()->zone->get_master_conn()->forward_iam_request(dpp, key, info,
1251 objv, MAX_REST_RESPONSE,
1252 &in_data, &response, y);
1253 if (ret < 0)
1254 return ret;
1255
1256 ldpp_dout(dpp, 20) << "response: " << response.c_str() << dendl;
1257
1258 std::string r = response.c_str();
1259 std::string str_to_search = "&quot;";
1260 std::string str_to_replace = "\"";
1261 boost::replace_all(r, str_to_search, str_to_replace);
1262 ldpp_dout(dpp, 20) << "r: " << r.c_str() << dendl;
1263
1264 if (parser && !parser->parse(r.c_str(), r.length(), 1)) {
1265 ldpp_dout(dpp, 0) << "ERROR: failed to parse response from master zonegroup" << dendl;
1266 return -EIO;
1267 }
1268
1269 return 0;
1270}
1271
20effc67 1272std::string RadosStore::zone_unique_id(uint64_t unique_num)
f67539c2 1273{
20effc67 1274 return svc()->zone_utils->unique_id(unique_num);
f67539c2
TL
1275}
1276
20effc67 1277std::string RadosStore::zone_unique_trans_id(const uint64_t unique_num)
f67539c2 1278{
20effc67
TL
1279 return svc()->zone_utils->unique_trans_id(unique_num);
1280}
f67539c2 1281
1e59de90
TL
1282int RadosStore::get_zonegroup(const std::string& id,
1283 std::unique_ptr<ZoneGroup>* zonegroup)
1284{
1285 ZoneGroup* zg;
1286 RGWZoneGroup rzg;
1287 int r = svc()->zone->get_zonegroup(id, rzg);
1288 if (r < 0)
1289 return r;
1290
1291 zg = new RadosZoneGroup(this, rzg);
1292 if (!zg)
1293 return -ENOMEM;
1294
1295 zonegroup->reset(zg);
1296 return 0;
1297}
1298
1299int RadosStore::list_all_zones(const DoutPrefixProvider* dpp, std::list<std::string>& zone_ids)
1300{
1301 return svc()->zone->list_zones(dpp, zone_ids);
1302}
1303
20effc67
TL
1304int RadosStore::cluster_stat(RGWClusterStat& stats)
1305{
1306 rados_cluster_stat_t rados_stats;
1307 int ret;
f67539c2 1308
20effc67 1309 ret = rados->get_rados_handle()->cluster_stat(rados_stats);
f67539c2
TL
1310 if (ret < 0)
1311 return ret;
1312
20effc67
TL
1313 stats.kb = rados_stats.kb;
1314 stats.kb_used = rados_stats.kb_used;
1315 stats.kb_avail = rados_stats.kb_avail;
1316 stats.num_objects = rados_stats.num_objects;
f67539c2
TL
1317
1318 return ret;
1319}
1320
20effc67 1321std::unique_ptr<Lifecycle> RadosStore::get_lifecycle(void)
f67539c2 1322{
20effc67 1323 return std::make_unique<RadosLifecycle>(this);
f67539c2
TL
1324}
1325
20effc67 1326std::unique_ptr<Completions> RadosStore::get_completions(void)
f67539c2 1327{
20effc67 1328 return std::make_unique<RadosCompletions>();
f67539c2
TL
1329}
1330
20effc67 1331std::unique_ptr<Notification> RadosStore::get_notification(
1e59de90 1332 rgw::sal::Object* obj, rgw::sal::Object* src_obj, req_state* s, rgw::notify::EventType event_type, optional_yield y, const std::string* object_name)
f67539c2 1333{
1e59de90 1334 return std::make_unique<RadosNotification>(s, this, obj, src_obj, s, event_type, y, object_name);
f67539c2
TL
1335}
1336
1e59de90 1337std::unique_ptr<Notification> RadosStore::get_notification(const DoutPrefixProvider* dpp, rgw::sal::Object* obj, rgw::sal::Object* src_obj, rgw::notify::EventType event_type, rgw::sal::Bucket* _bucket, std::string& _user_id, std::string& _user_tenant, std::string& _req_id, optional_yield y)
f67539c2 1338{
1e59de90
TL
1339 return std::make_unique<RadosNotification>(dpp, this, obj, src_obj, event_type, _bucket, _user_id, _user_tenant, _req_id, y);
1340}
1341
1342std::string RadosStore::topics_oid(const std::string& tenant) const {
1343 return pubsub_oid_prefix + tenant;
1344}
1345
1346int RadosStore::read_topics(const std::string& tenant, rgw_pubsub_topics& topics, RGWObjVersionTracker* objv_tracker,
1347 optional_yield y, const DoutPrefixProvider *dpp) {
1348 bufferlist bl;
1349 const int ret = rgw_get_system_obj(svc()->sysobj,
1350 svc()->zone->get_zone_params().log_pool,
1351 topics_oid(tenant),
1352 bl,
1353 objv_tracker,
1354 nullptr, y, dpp, nullptr);
1355 if (ret < 0) {
1356 return ret;
1357 }
1358
1359 auto iter = bl.cbegin();
1360 try {
1361 decode(topics, iter);
1362 } catch (buffer::error& err) {
1363 ldpp_dout(dpp, 20) << " failed to decode topics from oid: " << topics_oid(tenant) <<
1364 ". error: " << err.what() << dendl;
1365 return -EIO;
1366 }
1367
1368 return 0;
1369}
1370
1371int RadosStore::write_topics(const std::string& tenant, const rgw_pubsub_topics& topics, RGWObjVersionTracker* objv_tracker,
1372 optional_yield y, const DoutPrefixProvider *dpp) {
1373 bufferlist bl;
1374 encode(topics, bl);
1375
1376 return rgw_put_system_obj(dpp, svc()->sysobj,
1377 svc()->zone->get_zone_params().log_pool,
1378 topics_oid(tenant),
1379 bl, false, objv_tracker, real_time(), y);
1380}
1381
1382int RadosStore::remove_topics(const std::string& tenant, RGWObjVersionTracker* objv_tracker,
1383 optional_yield y, const DoutPrefixProvider *dpp) {
1384 return rgw_delete_system_obj(dpp, svc()->sysobj,
1385 svc()->zone->get_zone_params().log_pool,
1386 topics_oid(tenant),
1387 objv_tracker, y);
20effc67 1388}
f67539c2 1389
20effc67
TL
1390int RadosStore::delete_raw_obj(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj)
1391{
1392 return rados->delete_raw_obj(dpp, obj);
1393}
f67539c2 1394
20effc67
TL
1395int RadosStore::delete_raw_obj_aio(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, Completions* aio)
1396{
1397 RadosCompletions* raio = static_cast<RadosCompletions*>(aio);
f67539c2 1398
20effc67 1399 return rados->delete_raw_obj_aio(dpp, obj, raio->handles);
f67539c2
TL
1400}
1401
20effc67
TL
1402void RadosStore::get_raw_obj(const rgw_placement_rule& placement_rule, const rgw_obj& obj, rgw_raw_obj* raw_obj)
1403{
1404 rados->obj_to_raw(placement_rule, obj, raw_obj);
1405}
1406
1407int RadosStore::get_raw_chunk_size(const DoutPrefixProvider* dpp, const rgw_raw_obj& obj, uint64_t* chunk_size)
1408{
1409 return rados->get_max_chunk_size(obj.pool, chunk_size, dpp);
1410}
1411
1e59de90
TL
1412int RadosStore::initialize(CephContext *cct, const DoutPrefixProvider *dpp)
1413{
1414 std::unique_ptr<ZoneGroup> zg =
1415 std::make_unique<RadosZoneGroup>(this, svc()->zone->get_zonegroup());
1416 zone = make_unique<RadosZone>(this, std::move(zg));
1417 return 0;
1418}
1419
20effc67
TL
1420int RadosStore::log_usage(const DoutPrefixProvider *dpp, map<rgw_user_bucket, RGWUsageBatch>& usage_info)
1421{
1422 return rados->log_usage(dpp, usage_info);
1423}
1424
1425int RadosStore::log_op(const DoutPrefixProvider *dpp, std::string& oid, bufferlist& bl)
1426{
1427 rgw_raw_obj obj(svc()->zone->get_zone_params().log_pool, oid);
1428
1429 int ret = rados->append_async(dpp, obj, bl.length(), bl);
1430 if (ret == -ENOENT) {
1431 ret = rados->create_pool(dpp, svc()->zone->get_zone_params().log_pool);
1432 if (ret < 0)
1433 return ret;
1434 // retry
1435 ret = rados->append_async(dpp, obj, bl.length(), bl);
1436 }
1437
1438 return ret;
1439}
1440
1441int RadosStore::register_to_service_map(const DoutPrefixProvider *dpp, const std::string& daemon_type,
1442 const map<std::string, std::string>& meta)
1443{
1444 return rados->register_to_service_map(dpp, daemon_type, meta);
1445}
1446
1e59de90 1447void RadosStore::get_quota(RGWQuota& quota)
20effc67 1448{
1e59de90
TL
1449 quota.bucket_quota = svc()->quota->get_bucket_quota();
1450 quota.user_quota = svc()->quota->get_user_quota();
20effc67
TL
1451}
1452
1453void RadosStore::get_ratelimit(RGWRateLimitInfo& bucket_ratelimit, RGWRateLimitInfo& user_ratelimit, RGWRateLimitInfo& anon_ratelimit)
1454{
1455 bucket_ratelimit = svc()->zone->get_current_period().get_config().bucket_ratelimit;
1456 user_ratelimit = svc()->zone->get_current_period().get_config().user_ratelimit;
1457 anon_ratelimit = svc()->zone->get_current_period().get_config().anon_ratelimit;
1458}
1459
1460int RadosStore::set_buckets_enabled(const DoutPrefixProvider* dpp, vector<rgw_bucket>& buckets, bool enabled)
1461{
1462 return rados->set_buckets_enabled(buckets, enabled, dpp);
1463}
1464
1465int RadosStore::get_sync_policy_handler(const DoutPrefixProvider* dpp,
1466 std::optional<rgw_zone_id> zone,
1467 std::optional<rgw_bucket> bucket,
1468 RGWBucketSyncPolicyHandlerRef* phandler,
1469 optional_yield y)
1470{
1471 return ctl()->bucket->get_sync_policy_handler(zone, bucket, phandler, y, dpp);
1472}
1473
1474RGWDataSyncStatusManager* RadosStore::get_data_sync_manager(const rgw_zone_id& source_zone)
1475{
1476 return rados->get_data_sync_manager(source_zone);
1477}
1478
1479int RadosStore::read_all_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch,
1480 uint32_t max_entries, bool* is_truncated,
1481 RGWUsageIter& usage_iter,
1482 map<rgw_user_bucket, rgw_usage_log_entry>& usage)
1483{
1484 rgw_user uid;
1485 std::string bucket_name;
1486
1487 return rados->read_usage(dpp, uid, bucket_name, start_epoch, end_epoch, max_entries,
1488 is_truncated, usage_iter, usage);
1489}
1490
1491int RadosStore::trim_all_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch)
1492{
1493 rgw_user uid;
1494 std::string bucket_name;
1495
1496 return rados->trim_usage(dpp, uid, bucket_name, start_epoch, end_epoch);
1497}
1498
1499int RadosStore::get_config_key_val(std::string name, bufferlist* bl)
1500{
1501 return svc()->config_key->get(name, true, bl);
1502}
1503
1504int RadosStore::meta_list_keys_init(const DoutPrefixProvider *dpp, const std::string& section, const std::string& marker, void** phandle)
1505{
1506 return ctl()->meta.mgr->list_keys_init(dpp, section, marker, phandle);
1507}
1508
1509int RadosStore::meta_list_keys_next(const DoutPrefixProvider *dpp, void* handle, int max, list<std::string>& keys, bool* truncated)
1510{
1511 return ctl()->meta.mgr->list_keys_next(dpp, handle, max, keys, truncated);
1512}
1513
1514void RadosStore::meta_list_keys_complete(void* handle)
1515{
1516 ctl()->meta.mgr->list_keys_complete(handle);
1517}
1518
1519std::string RadosStore::meta_get_marker(void* handle)
1520{
1521 return ctl()->meta.mgr->get_marker(handle);
1522}
1523
1524int RadosStore::meta_remove(const DoutPrefixProvider* dpp, std::string& metadata_key, optional_yield y)
1525{
1526 return ctl()->meta.mgr->remove(metadata_key, y, dpp);
1527}
1528
1529void RadosStore::finalize(void)
1530{
1531 if (rados)
1532 rados->finalize();
1533}
1534
1e59de90
TL
1535void RadosStore::register_admin_apis(RGWRESTMgr* mgr)
1536{
1537 mgr->register_resource("user", new RGWRESTMgr_User);
1538 mgr->register_resource("bucket", new RGWRESTMgr_Bucket);
1539 /*Registering resource for /admin/metadata */
1540 mgr->register_resource("metadata", new RGWRESTMgr_Metadata);
1541 mgr->register_resource("log", new RGWRESTMgr_Log);
1542 /* XXX These may become global when cbodley is done with his zone work */
1543 mgr->register_resource("config", new RGWRESTMgr_Config);
1544 mgr->register_resource("realm", new RGWRESTMgr_Realm);
1545 mgr->register_resource("ratelimit", new RGWRESTMgr_Ratelimit);
1546}
1547
1548std::unique_ptr<LuaManager> RadosStore::get_lua_manager()
20effc67 1549{
1e59de90 1550 return std::make_unique<RadosLuaManager>(this);
20effc67
TL
1551}
1552
1553std::unique_ptr<RGWRole> RadosStore::get_role(std::string name,
1554 std::string tenant,
1555 std::string path,
1556 std::string trust_policy,
1557 std::string max_session_duration_str,
1558 std::multimap<std::string,std::string> tags)
1559{
1560 return std::make_unique<RadosRole>(this, name, tenant, path, trust_policy, max_session_duration_str, tags);
1561}
1562
1563std::unique_ptr<RGWRole> RadosStore::get_role(std::string id)
1564{
1565 return std::make_unique<RadosRole>(this, id);
1566}
1567
39ae355f
TL
1568std::unique_ptr<RGWRole> RadosStore::get_role(const RGWRoleInfo& info)
1569{
1570 return std::make_unique<RadosRole>(this, info);
1571}
1572
20effc67
TL
1573int RadosStore::get_roles(const DoutPrefixProvider *dpp,
1574 optional_yield y,
1575 const std::string& path_prefix,
1576 const std::string& tenant,
1577 vector<std::unique_ptr<RGWRole>>& roles)
1578{
1e59de90 1579 auto pool = svc()->zone->get_zone_params().roles_pool;
20effc67
TL
1580 std::string prefix;
1581
1582 // List all roles if path prefix is empty
1583 if (! path_prefix.empty()) {
1584 prefix = tenant + RGWRole::role_path_oid_prefix + path_prefix;
1585 } else {
1586 prefix = tenant + RGWRole::role_path_oid_prefix;
1587 }
1588
1589 //Get the filtered objects
1590 list<std::string> result;
1591 bool is_truncated;
1592 RGWListRawObjsCtx ctx;
1593 do {
1594 list<std::string> oids;
1595 int r = rados->list_raw_objects(dpp, pool, prefix, 1000, ctx, oids, &is_truncated);
1596 if (r < 0) {
1597 ldpp_dout(dpp, 0) << "ERROR: listing filtered objects failed: "
1598 << prefix << ": " << cpp_strerror(-r) << dendl;
1599 return r;
1600 }
1601 for (const auto& iter : oids) {
1602 result.push_back(iter.substr(RGWRole::role_path_oid_prefix.size()));
1603 }
1604 } while (is_truncated);
1605
1606 for (const auto& it : result) {
1607 //Find the role oid prefix from the end
1608 size_t pos = it.rfind(RGWRole::role_oid_prefix);
1609 if (pos == std::string::npos) {
1610 continue;
1611 }
1612 // Split the result into path and info_oid + id
1613 std::string path = it.substr(0, pos);
1614
1615 /*Make sure that prefix is part of path (False results could've been returned)
1616 because of the role info oid + id appended to the path)*/
1617 if(path_prefix.empty() || path.find(path_prefix) != std::string::npos) {
1618 //Get id from info oid prefix + id
1619 std::string id = it.substr(pos + RGWRole::role_oid_prefix.length());
1620
1621 std::unique_ptr<rgw::sal::RGWRole> role = get_role(id);
1622 int ret = role->read_info(dpp, y);
1623 if (ret < 0) {
1624 return ret;
1625 }
1626 roles.push_back(std::move(role));
1627 }
1628 }
1629
1630 return 0;
1631}
1632
1633std::unique_ptr<RGWOIDCProvider> RadosStore::get_oidc_provider()
1634{
1635 return std::make_unique<RadosOIDCProvider>(this);
1636}
1637
1638int RadosStore::get_oidc_providers(const DoutPrefixProvider *dpp,
1639 const std::string& tenant,
1640 vector<std::unique_ptr<RGWOIDCProvider>>& providers)
1641{
1642 std::string prefix = tenant + RGWOIDCProvider::oidc_url_oid_prefix;
1e59de90 1643 auto pool = svc()->zone->get_zone_params().oidc_pool;
20effc67
TL
1644
1645 //Get the filtered objects
1646 list<std::string> result;
1647 bool is_truncated;
1648 RGWListRawObjsCtx ctx;
1649 do {
1650 list<std::string> oids;
1651 int r = rados->list_raw_objects(dpp, pool, prefix, 1000, ctx, oids, &is_truncated);
1652 if (r < 0) {
1653 ldpp_dout(dpp, 0) << "ERROR: listing filtered objects failed: OIDC pool: "
1654 << pool.name << ": " << prefix << ": " << cpp_strerror(-r) << dendl;
1655 return r;
1656 }
1657 for (const auto& iter : oids) {
1658 std::unique_ptr<rgw::sal::RGWOIDCProvider> provider = get_oidc_provider();
1659 bufferlist bl;
1660
1e59de90 1661 r = rgw_get_system_obj(svc()->sysobj, pool, iter, bl, nullptr, nullptr, null_yield, dpp);
20effc67
TL
1662 if (r < 0) {
1663 return r;
1664 }
1665
1666 try {
1667 using ceph::decode;
1668 auto iter = bl.cbegin();
1669 decode(*provider, iter);
1670 } catch (buffer::error& err) {
1671 ldpp_dout(dpp, 0) << "ERROR: failed to decode oidc provider info from pool: "
1672 << pool.name << ": " << iter << dendl;
1673 return -EIO;
1674 }
1675
1676 providers.push_back(std::move(provider));
1677 }
1678 } while (is_truncated);
1679
1680 return 0;
1681}
1682
1683std::unique_ptr<Writer> RadosStore::get_append_writer(const DoutPrefixProvider *dpp,
1684 optional_yield y,
1e59de90
TL
1685 rgw::sal::Object* obj,
1686 const rgw_user& owner,
20effc67
TL
1687 const rgw_placement_rule *ptail_placement_rule,
1688 const std::string& unique_tag,
1689 uint64_t position,
1690 uint64_t *cur_accounted_size)
1691{
1e59de90
TL
1692 RGWBucketInfo& bucket_info = obj->get_bucket()->get_info();
1693 RGWObjectCtx& obj_ctx = static_cast<RadosObject*>(obj)->get_ctx();
20effc67
TL
1694 auto aio = rgw::make_throttle(ctx()->_conf->rgw_put_obj_min_window_size, y);
1695 return std::make_unique<RadosAppendWriter>(dpp, y,
1e59de90
TL
1696 bucket_info, obj_ctx, obj->get_obj(),
1697 this, std::move(aio), owner,
20effc67
TL
1698 ptail_placement_rule,
1699 unique_tag, position,
1700 cur_accounted_size);
1701}
1702
1703std::unique_ptr<Writer> RadosStore::get_atomic_writer(const DoutPrefixProvider *dpp,
1704 optional_yield y,
1e59de90
TL
1705 rgw::sal::Object* obj,
1706 const rgw_user& owner,
20effc67
TL
1707 const rgw_placement_rule *ptail_placement_rule,
1708 uint64_t olh_epoch,
1709 const std::string& unique_tag)
1710{
1e59de90
TL
1711 RGWBucketInfo& bucket_info = obj->get_bucket()->get_info();
1712 RGWObjectCtx& obj_ctx = static_cast<RadosObject*>(obj)->get_ctx();
20effc67
TL
1713 auto aio = rgw::make_throttle(ctx()->_conf->rgw_put_obj_min_window_size, y);
1714 return std::make_unique<RadosAtomicWriter>(dpp, y,
1e59de90
TL
1715 bucket_info, obj_ctx, obj->get_obj(),
1716 this, std::move(aio), owner,
20effc67
TL
1717 ptail_placement_rule,
1718 olh_epoch, unique_tag);
1719}
1720
1e59de90
TL
1721const std::string& RadosStore::get_compression_type(const rgw_placement_rule& rule)
1722{
1723 return svc()->zone->get_zone_params().get_compression_type(rule);
1724}
1725
1726bool RadosStore::valid_placement(const rgw_placement_rule& rule)
1727{
1728 return svc()->zone->get_zone_params().valid_placement(rule);
1729}
1730
20effc67
TL
1731int RadosStore::get_obj_head_ioctx(const DoutPrefixProvider *dpp, const RGWBucketInfo& bucket_info, const rgw_obj& obj, librados::IoCtx* ioctx)
1732{
1733 return rados->get_obj_head_ioctx(dpp, bucket_info, obj, ioctx);
1734}
1735
1e59de90
TL
1736RadosObject::~RadosObject()
1737{
1738 if (rados_ctx_owned)
1739 delete rados_ctx;
1740}
20effc67 1741
1e59de90 1742int RadosObject::get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **pstate, optional_yield y, bool follow_olh)
20effc67 1743{
1e59de90
TL
1744 int ret = store->getRados()->get_obj_state(dpp, rados_ctx, bucket->get_info(), get_obj(), pstate, &manifest, follow_olh, y);
1745 if (ret < 0) {
1746 return ret;
1747 }
1748
1749 /* Don't overwrite obj, atomic, or prefetch */
1750 rgw_obj obj = get_obj();
1751 bool is_atomic = state.is_atomic;
1752 bool prefetch_data = state.prefetch_data;
1753
1754 state = **pstate;
1755
1756 state.obj = obj;
1757 state.is_atomic = is_atomic;
1758 state.prefetch_data = prefetch_data;
1759 return ret;
20effc67
TL
1760}
1761
1762int RadosObject::read_attrs(const DoutPrefixProvider* dpp, RGWRados::Object::Read &read_op, optional_yield y, rgw_obj* target_obj)
1763{
1e59de90 1764 read_op.params.attrs = &state.attrset;
20effc67 1765 read_op.params.target_obj = target_obj;
1e59de90
TL
1766 read_op.params.obj_size = &state.size;
1767 read_op.params.lastmod = &state.mtime;
20effc67
TL
1768
1769 return read_op.prepare(y, dpp);
1770}
1771
1e59de90 1772int RadosObject::set_obj_attrs(const DoutPrefixProvider* dpp, Attrs* setattrs, Attrs* delattrs, optional_yield y)
20effc67
TL
1773{
1774 Attrs empty;
1e59de90 1775 return store->getRados()->set_attrs(dpp, rados_ctx,
20effc67 1776 bucket->get_info(),
1e59de90 1777 get_obj(),
20effc67
TL
1778 setattrs ? *setattrs : empty,
1779 delattrs ? delattrs : nullptr,
1780 y);
1781}
1782
1e59de90 1783int RadosObject::get_obj_attrs(optional_yield y, const DoutPrefixProvider* dpp, rgw_obj* target_obj)
20effc67 1784{
1e59de90 1785 RGWRados::Object op_target(store->getRados(), bucket->get_info(), *rados_ctx, get_obj());
20effc67
TL
1786 RGWRados::Object::Read read_op(&op_target);
1787
1788 return read_attrs(dpp, read_op, y, target_obj);
1789}
1790
1e59de90 1791int RadosObject::modify_obj_attrs(const char* attr_name, bufferlist& attr_val, optional_yield y, const DoutPrefixProvider* dpp)
20effc67
TL
1792{
1793 rgw_obj target = get_obj();
1e59de90
TL
1794 rgw_obj save = get_obj();
1795 int r = get_obj_attrs(y, dpp, &target);
20effc67
TL
1796 if (r < 0) {
1797 return r;
1798 }
1e59de90
TL
1799
1800 /* Temporarily set target */
1801 state.obj = target;
1802 set_atomic();
1803 state.attrset[attr_name] = attr_val;
1804 r = set_obj_attrs(dpp, &state.attrset, nullptr, y);
1805 /* Restore target */
1806 state.obj = save;
1807
1808 return r;
20effc67
TL
1809}
1810
1e59de90 1811int RadosObject::delete_obj_attrs(const DoutPrefixProvider* dpp, const char* attr_name, optional_yield y)
20effc67
TL
1812{
1813 Attrs rmattr;
1814 bufferlist bl;
1815
1e59de90 1816 set_atomic();
20effc67 1817 rmattr[attr_name] = bl;
1e59de90 1818 return set_obj_attrs(dpp, nullptr, &rmattr, y);
20effc67
TL
1819}
1820
1821bool RadosObject::is_expired() {
1e59de90
TL
1822 auto iter = state.attrset.find(RGW_ATTR_DELETE_AT);
1823 if (iter == state.attrset.end()) {
1824 return false;
1825 }
1826 utime_t delete_at;
1827 try {
1828 auto bufit = iter->second.cbegin();
1829 decode(delete_at, bufit);
1830 } catch (buffer::error& err) {
1831 ldout(store->ctx(), 0) << "ERROR: " << __func__ << ": failed to decode " RGW_ATTR_DELETE_AT " attr" << dendl;
1832 return false;
20effc67
TL
1833 }
1834
1e59de90 1835 return delete_at <= ceph_clock_now() && !delete_at.is_zero();
20effc67
TL
1836}
1837
1838void RadosObject::gen_rand_obj_instance_name()
1839{
1e59de90 1840 store->getRados()->gen_rand_obj_instance_name(&state.obj.key);
20effc67
TL
1841}
1842
1843void RadosObject::raw_obj_to_obj(const rgw_raw_obj& raw_obj)
1844{
1845 rgw_obj tobj = get_obj();
1846 RGWSI_Tier_RADOS::raw_obj_to_obj(get_bucket()->get_key(), raw_obj, &tobj);
1847 set_key(tobj.key);
1848}
1849
1850void RadosObject::get_raw_obj(rgw_raw_obj* raw_obj)
1851{
1852 store->getRados()->obj_to_raw((bucket->get_info()).placement_rule, get_obj(), raw_obj);
1853}
1854
1855int RadosObject::omap_get_vals(const DoutPrefixProvider *dpp, const std::string& marker, uint64_t count,
1856 std::map<std::string, bufferlist> *m,
1857 bool* pmore, optional_yield y)
1858{
20effc67
TL
1859 rgw_raw_obj raw_obj;
1860 get_raw_obj(&raw_obj);
1e59de90 1861 auto sysobj = store->svc()->sysobj->get_obj(raw_obj);
20effc67
TL
1862
1863 return sysobj.omap().get_vals(dpp, marker, count, m, pmore, y);
1864}
1865
1866int RadosObject::omap_get_all(const DoutPrefixProvider *dpp, std::map<std::string, bufferlist> *m,
1867 optional_yield y)
1868{
20effc67
TL
1869 rgw_raw_obj raw_obj;
1870 get_raw_obj(&raw_obj);
1e59de90 1871 auto sysobj = store->svc()->sysobj->get_obj(raw_obj);
20effc67
TL
1872
1873 return sysobj.omap().get_all(dpp, m, y);
1874}
1875
1876int RadosObject::omap_get_vals_by_keys(const DoutPrefixProvider *dpp, const std::string& oid,
1877 const std::set<std::string>& keys,
1878 Attrs* vals)
1879{
1880 int ret;
1881 rgw_raw_obj head_obj;
1882 librados::IoCtx cur_ioctx;
1883 rgw_obj obj = get_obj();
1884
1885 store->getRados()->obj_to_raw(bucket->get_placement_rule(), obj, &head_obj);
1886 ret = store->get_obj_head_ioctx(dpp, bucket->get_info(), obj, &cur_ioctx);
1887 if (ret < 0) {
1888 return ret;
1889 }
1890
1891 return cur_ioctx.omap_get_vals_by_keys(oid, keys, vals);
1892}
1893
1894int RadosObject::omap_set_val_by_key(const DoutPrefixProvider *dpp, const std::string& key, bufferlist& val,
1895 bool must_exist, optional_yield y)
1896{
1897 rgw_raw_obj raw_meta_obj;
1898 rgw_obj obj = get_obj();
1899
1900 store->getRados()->obj_to_raw(bucket->get_placement_rule(), obj, &raw_meta_obj);
1901
1e59de90 1902 auto sysobj = store->svc()->sysobj->get_obj(raw_meta_obj);
20effc67
TL
1903
1904 return sysobj.omap().set_must_exist(must_exist).set(dpp, key, val, y);
1905}
1906
39ae355f
TL
1907int RadosObject::chown(User& new_user, const DoutPrefixProvider* dpp, optional_yield y)
1908{
1e59de90 1909 int r = get_obj_attrs(y, dpp);
39ae355f
TL
1910 if (r < 0) {
1911 ldpp_dout(dpp, 0) << "ERROR: failed to read object attrs " << get_name() << cpp_strerror(-r) << dendl;
1912 return r;
1913 }
1914
1915 const auto& aiter = get_attrs().find(RGW_ATTR_ACL);
1916 if (aiter == get_attrs().end()) {
1917 ldpp_dout(dpp, 0) << "ERROR: no acls found for object " << get_name() << dendl;
1918 return -EINVAL;
1919 }
1920
1921 bufferlist& bl = aiter->second;
1922 RGWAccessControlPolicy policy(store->ctx());
1923 ACLOwner owner;
1924 auto bliter = bl.cbegin();
1925 try {
1926 policy.decode(bliter);
1927 owner = policy.get_owner();
1928 } catch (buffer::error& err) {
1929 ldpp_dout(dpp, 0) << "ERROR: decode policy failed" << err.what()
1930 << dendl;
1931 return -EIO;
1932 }
1933
1934 //Get the ACL from the policy
1935 RGWAccessControlList& acl = policy.get_acl();
1936
1937 //Remove grant that is set to old owner
1938 acl.remove_canon_user_grant(owner.get_id());
1939
1940 //Create a grant and add grant
1941 ACLGrant grant;
1942 grant.set_canon(new_user.get_id(), new_user.get_display_name(), RGW_PERM_FULL_CONTROL);
1943 acl.add_grant(&grant);
1944
1945 //Update the ACL owner to the new user
1946 owner.set_id(new_user.get_id());
1947 owner.set_name(new_user.get_display_name());
1948 policy.set_owner(owner);
1949
1950 bl.clear();
1951 encode(policy, bl);
1952
1e59de90 1953 set_atomic();
39ae355f
TL
1954 map<string, bufferlist> attrs;
1955 attrs[RGW_ATTR_ACL] = bl;
1e59de90 1956 r = set_obj_attrs(dpp, &attrs, nullptr, y);
39ae355f
TL
1957 if (r < 0) {
1958 ldpp_dout(dpp, 0) << "ERROR: modify attr failed " << cpp_strerror(-r) << dendl;
1959 return r;
1960 }
1961
1962 return 0;
1963}
1964
1e59de90 1965std::unique_ptr<MPSerializer> RadosObject::get_serializer(const DoutPrefixProvider *dpp, const std::string& lock_name)
20effc67 1966{
1e59de90 1967 return std::make_unique<MPRadosSerializer>(dpp, store, this, lock_name);
20effc67
TL
1968}
1969
1e59de90
TL
1970int RadosObject::transition(Bucket* bucket,
1971 const rgw_placement_rule& placement_rule,
1972 const real_time& mtime,
1973 uint64_t olh_epoch,
1974 const DoutPrefixProvider* dpp,
1975 optional_yield y)
1976{
1977 return store->getRados()->transition_obj(*rados_ctx, bucket->get_info(), get_obj(), placement_rule, mtime, olh_epoch, dpp, y);
1978}
1979
1980int RadosObject::transition_to_cloud(Bucket* bucket,
1981 rgw::sal::PlacementTier* tier,
1982 rgw_bucket_dir_entry& o,
1983 std::set<std::string>& cloud_targets,
1984 CephContext* cct,
1985 bool update_object,
1986 const DoutPrefixProvider* dpp,
1987 optional_yield y)
20effc67 1988{
1e59de90
TL
1989 /* init */
1990 rgw::sal::RadosPlacementTier* rtier = static_cast<rgw::sal::RadosPlacementTier*>(tier);
1991 string id = "cloudid";
1992 string endpoint = rtier->get_rt().t.s3.endpoint;
1993 RGWAccessKey key = rtier->get_rt().t.s3.key;
1994 string region = rtier->get_rt().t.s3.region;
1995 HostStyle host_style = rtier->get_rt().t.s3.host_style;
1996 string bucket_name = rtier->get_rt().t.s3.target_path;
1997 const rgw::sal::ZoneGroup& zonegroup = store->get_zone()->get_zonegroup();
1998
1999 if (bucket_name.empty()) {
2000 bucket_name = "rgwx-" + zonegroup.get_name() + "-" + tier->get_storage_class() +
2001 "-cloud-bucket";
2002 boost::algorithm::to_lower(bucket_name);
2003 }
2004
2005 /* Create RGW REST connection */
2006 S3RESTConn conn(cct, id, { endpoint }, key, zonegroup.get_id(), region, host_style);
2007
2008 RGWLCCloudTierCtx tier_ctx(cct, dpp, o, store, bucket->get_info(),
2009 this, conn, bucket_name,
2010 rtier->get_rt().t.s3.target_storage_class);
2011 tier_ctx.acl_mappings = rtier->get_rt().t.s3.acl_mappings;
2012 tier_ctx.multipart_min_part_size = rtier->get_rt().t.s3.multipart_min_part_size;
2013 tier_ctx.multipart_sync_threshold = rtier->get_rt().t.s3.multipart_sync_threshold;
2014 tier_ctx.storage_class = tier->get_storage_class();
2015
2016 ldpp_dout(dpp, 0) << "Transitioning object(" << o.key << ") to the cloud endpoint(" << endpoint << ")" << dendl;
2017
2018 /* Transition object to cloud end point */
2019 int ret = rgw_cloud_tier_transfer_object(tier_ctx, cloud_targets);
2020
2021 if (ret < 0) {
2022 ldpp_dout(dpp, 0) << "ERROR: failed to transfer object(" << o.key << ") to the cloud endpoint(" << endpoint << ") ret=" << ret << dendl;
2023 return ret;
2024 }
2025
2026 if (update_object) {
2027 real_time read_mtime;
2028
2029 std::unique_ptr<rgw::sal::Object::ReadOp> read_op(get_read_op());
2030 read_op->params.lastmod = &read_mtime;
2031
2032 ret = read_op->prepare(y, dpp);
2033 if (ret < 0) {
2034 ldpp_dout(dpp, 0) << "ERROR: Updating tier object(" << o.key << ") failed ret=" << ret << dendl;
2035 return ret;
2036 }
2037
2038 if (read_mtime != tier_ctx.o.meta.mtime) {
2039 /* raced */
2040 ldpp_dout(dpp, 0) << "ERROR: Updating tier object(" << o.key << ") failed ret=" << -ECANCELED << dendl;
2041 return -ECANCELED;
2042 }
2043
2044 rgw_placement_rule target_placement;
2045 target_placement.inherit_from(tier_ctx.bucket_info.placement_rule);
2046 target_placement.storage_class = tier->get_storage_class();
2047
2048 ret = write_cloud_tier(dpp, y, tier_ctx.o.versioned_epoch,
2049 tier, tier_ctx.is_multipart_upload,
2050 target_placement, tier_ctx.obj);
2051
2052 }
2053
2054 return ret;
2055}
2056
2057int RadosObject::write_cloud_tier(const DoutPrefixProvider* dpp,
2058 optional_yield y,
2059 uint64_t olh_epoch,
2060 PlacementTier* tier,
2061 bool is_multipart_upload,
2062 rgw_placement_rule& target_placement,
2063 Object* head_obj)
2064{
2065 rgw::sal::RadosPlacementTier* rtier = static_cast<rgw::sal::RadosPlacementTier*>(tier);
2066 map<string, bufferlist> attrs = get_attrs();
2067 RGWRados::Object op_target(store->getRados(), bucket->get_info(), *rados_ctx, get_obj());
2068 RGWRados::Object::Write obj_op(&op_target);
2069
2070 obj_op.meta.modify_tail = true;
2071 obj_op.meta.flags = PUT_OBJ_CREATE;
2072 obj_op.meta.category = RGWObjCategory::CloudTiered;
2073 obj_op.meta.delete_at = real_time();
2074 bufferlist blo;
2075 obj_op.meta.data = &blo;
2076 obj_op.meta.if_match = NULL;
2077 obj_op.meta.if_nomatch = NULL;
2078 obj_op.meta.user_data = NULL;
2079 obj_op.meta.zones_trace = NULL;
2080 obj_op.meta.delete_at = real_time();
2081 obj_op.meta.olh_epoch = olh_epoch;
2082
2083 RGWObjManifest *pmanifest;
2084 RGWObjManifest manifest;
2085
2086 pmanifest = &manifest;
2087 RGWObjTier tier_config;
2088 tier_config.name = tier->get_storage_class();
2089 tier_config.tier_placement = rtier->get_rt();
2090 tier_config.is_multipart_upload = is_multipart_upload;
2091
2092 pmanifest->set_tier_type("cloud-s3");
2093 pmanifest->set_tier_config(tier_config);
2094
2095 /* check if its necessary */
2096 pmanifest->set_head(target_placement, head_obj->get_obj(), 0);
2097 pmanifest->set_tail_placement(target_placement, head_obj->get_obj().bucket);
2098 pmanifest->set_obj_size(0);
2099 obj_op.meta.manifest = pmanifest;
2100
2101 /* update storage class */
2102 bufferlist bl;
2103 bl.append(tier->get_storage_class());
2104 attrs[RGW_ATTR_STORAGE_CLASS] = bl;
2105
2106 attrs.erase(RGW_ATTR_ID_TAG);
2107 attrs.erase(RGW_ATTR_TAIL_TAG);
2108
2109 return obj_op.write_meta(dpp, 0, 0, attrs, y);
20effc67
TL
2110}
2111
2112int RadosObject::get_max_chunk_size(const DoutPrefixProvider* dpp, rgw_placement_rule placement_rule, uint64_t* max_chunk_size, uint64_t* alignment)
2113{
2114 return store->getRados()->get_max_chunk_size(placement_rule, get_obj(), max_chunk_size, dpp, alignment);
2115}
2116
2117void RadosObject::get_max_aligned_size(uint64_t size, uint64_t alignment,
2118 uint64_t* max_size)
2119{
2120 store->getRados()->get_max_aligned_size(size, alignment, max_size);
2121}
2122
2123bool RadosObject::placement_rules_match(rgw_placement_rule& r1, rgw_placement_rule& r2)
2124{
2125 rgw_obj obj;
2126 rgw_pool p1, p2;
2127
2128 obj = get_obj();
2129
2130 if (r1 == r2)
2131 return true;
2132
2133 if (!store->getRados()->get_obj_data_pool(r1, obj, &p1)) {
2134 return false;
2135 }
2136 if (!store->getRados()->get_obj_data_pool(r2, obj, &p2)) {
2137 return false;
2138 }
2139
2140 return p1 == p2;
2141}
2142
1e59de90 2143int RadosObject::dump_obj_layout(const DoutPrefixProvider *dpp, optional_yield y, Formatter* f)
20effc67
TL
2144{
2145 int ret;
1e59de90 2146 RGWObjManifest *amanifest{nullptr};
20effc67
TL
2147 rgw_raw_obj head_obj;
2148
1e59de90 2149 RGWRados::Object op_target(store->getRados(), bucket->get_info(), *rados_ctx, get_obj());
20effc67
TL
2150 RGWRados::Object::Read parent_op(&op_target);
2151 uint64_t obj_size;
2152
2153 parent_op.params.obj_size = &obj_size;
2154 parent_op.params.attrs = &get_attrs();
2155
2156 ret = parent_op.prepare(y, dpp);
2157 if (ret < 0) {
2158 return ret;
2159 }
2160
2161 head_obj = parent_op.state.head_obj;
2162
1e59de90 2163 ret = op_target.get_manifest(dpp, &amanifest, y);
20effc67
TL
2164 if (ret < 0) {
2165 return ret;
2166 }
2167
2168 ::encode_json("head", head_obj, f);
1e59de90 2169 ::encode_json("manifest", *amanifest, f);
20effc67 2170 f->open_array_section("data_location");
1e59de90 2171 for (auto miter = amanifest->obj_begin(dpp); miter != amanifest->obj_end(dpp); ++miter) {
20effc67 2172 f->open_object_section("obj");
1e59de90 2173 rgw_raw_obj raw_loc = miter.get_location().get_raw_obj(store->getRados());
20effc67 2174 uint64_t ofs = miter.get_ofs();
1e59de90 2175 uint64_t left = amanifest->get_obj_size() - ofs;
20effc67
TL
2176 ::encode_json("ofs", miter.get_ofs(), f);
2177 ::encode_json("loc", raw_loc, f);
2178 ::encode_json("loc_ofs", miter.location_ofs(), f);
2179 uint64_t loc_size = miter.get_stripe_size();
2180 if (loc_size > left) {
2181 loc_size = left;
2182 }
2183 ::encode_json("loc_size", loc_size, f);
2184 f->close_section();
2185 }
2186 f->close_section();
2187
2188 return 0;
2189}
2190
1e59de90 2191std::unique_ptr<Object::ReadOp> RadosObject::get_read_op()
20effc67 2192{
1e59de90 2193 return std::make_unique<RadosObject::RadosReadOp>(this, rados_ctx);
20effc67
TL
2194}
2195
2196RadosObject::RadosReadOp::RadosReadOp(RadosObject *_source, RGWObjectCtx *_rctx) :
2197 source(_source),
2198 rctx(_rctx),
2199 op_target(_source->store->getRados(),
2200 _source->get_bucket()->get_info(),
2201 *static_cast<RGWObjectCtx *>(rctx),
2202 _source->get_obj()),
2203 parent_op(&op_target)
2204{ }
2205
2206int RadosObject::RadosReadOp::prepare(optional_yield y, const DoutPrefixProvider* dpp)
2207{
2208 uint64_t obj_size;
2209
2210 parent_op.conds.mod_ptr = params.mod_ptr;
2211 parent_op.conds.unmod_ptr = params.unmod_ptr;
2212 parent_op.conds.high_precision_time = params.high_precision_time;
2213 parent_op.conds.mod_zone_id = params.mod_zone_id;
2214 parent_op.conds.mod_pg_ver = params.mod_pg_ver;
2215 parent_op.conds.if_match = params.if_match;
2216 parent_op.conds.if_nomatch = params.if_nomatch;
2217 parent_op.params.lastmod = params.lastmod;
2218 parent_op.params.target_obj = params.target_obj;
2219 parent_op.params.obj_size = &obj_size;
2220 parent_op.params.attrs = &source->get_attrs();
2221
2222 int ret = parent_op.prepare(y, dpp);
2223 if (ret < 0)
2224 return ret;
2225
2226 source->set_key(parent_op.state.obj.key);
2227 source->set_obj_size(obj_size);
2228
2229 return ret;
2230}
2231
2232int RadosObject::RadosReadOp::read(int64_t ofs, int64_t end, bufferlist& bl, optional_yield y, const DoutPrefixProvider* dpp)
2233{
2234 return parent_op.read(ofs, end, bl, y, dpp);
2235}
2236
2237int RadosObject::RadosReadOp::get_attr(const DoutPrefixProvider* dpp, const char* name, bufferlist& dest, optional_yield y)
2238{
2239 return parent_op.get_attr(dpp, name, dest, y);
2240}
2241
1e59de90 2242std::unique_ptr<Object::DeleteOp> RadosObject::get_delete_op()
20effc67 2243{
1e59de90 2244 return std::make_unique<RadosObject::RadosDeleteOp>(this);
20effc67
TL
2245}
2246
1e59de90 2247RadosObject::RadosDeleteOp::RadosDeleteOp(RadosObject *_source) :
20effc67 2248 source(_source),
20effc67
TL
2249 op_target(_source->store->getRados(),
2250 _source->get_bucket()->get_info(),
1e59de90 2251 _source->get_ctx(),
20effc67
TL
2252 _source->get_obj()),
2253 parent_op(&op_target)
2254{ }
2255
2256int RadosObject::RadosDeleteOp::delete_obj(const DoutPrefixProvider* dpp, optional_yield y)
2257{
2258 parent_op.params.bucket_owner = params.bucket_owner.get_id();
2259 parent_op.params.versioning_status = params.versioning_status;
2260 parent_op.params.obj_owner = params.obj_owner;
2261 parent_op.params.olh_epoch = params.olh_epoch;
2262 parent_op.params.marker_version_id = params.marker_version_id;
2263 parent_op.params.bilog_flags = params.bilog_flags;
2264 parent_op.params.remove_objs = params.remove_objs;
2265 parent_op.params.expiration_time = params.expiration_time;
2266 parent_op.params.unmod_since = params.unmod_since;
2267 parent_op.params.mtime = params.mtime;
2268 parent_op.params.high_precision_time = params.high_precision_time;
2269 parent_op.params.zones_trace = params.zones_trace;
2270 parent_op.params.abortmp = params.abortmp;
2271 parent_op.params.parts_accounted_size = params.parts_accounted_size;
2272
2273 int ret = parent_op.delete_obj(y, dpp);
2274 if (ret < 0)
2275 return ret;
2276
2277 result.delete_marker = parent_op.result.delete_marker;
2278 result.version_id = parent_op.result.version_id;
2279
2280 return ret;
2281}
2282
2283int RadosObject::delete_object(const DoutPrefixProvider* dpp,
20effc67
TL
2284 optional_yield y,
2285 bool prevent_versioning)
2286{
1e59de90 2287 RGWRados::Object del_target(store->getRados(), bucket->get_info(), *rados_ctx, get_obj());
20effc67
TL
2288 RGWRados::Object::Delete del_op(&del_target);
2289
2290 del_op.params.bucket_owner = bucket->get_info().owner;
2291 del_op.params.versioning_status = prevent_versioning ? 0 : bucket->get_info().versioning_status();
2292
2293 return del_op.delete_obj(y, dpp);
2294}
2295
2296int RadosObject::delete_obj_aio(const DoutPrefixProvider* dpp, RGWObjState* astate,
2297 Completions* aio, bool keep_index_consistent,
2298 optional_yield y)
2299{
2300 RadosCompletions* raio = static_cast<RadosCompletions*>(aio);
2301
2302 return store->getRados()->delete_obj_aio(dpp, get_obj(), bucket->get_info(), astate,
2303 raio->handles, keep_index_consistent, y);
2304}
2305
1e59de90 2306int RadosObject::copy_object(User* user,
20effc67
TL
2307 req_info* info,
2308 const rgw_zone_id& source_zone,
2309 rgw::sal::Object* dest_object,
2310 rgw::sal::Bucket* dest_bucket,
2311 rgw::sal::Bucket* src_bucket,
2312 const rgw_placement_rule& dest_placement,
2313 ceph::real_time* src_mtime,
2314 ceph::real_time* mtime,
2315 const ceph::real_time* mod_ptr,
2316 const ceph::real_time* unmod_ptr,
2317 bool high_precision_time,
2318 const char* if_match,
2319 const char* if_nomatch,
f67539c2
TL
2320 AttrsMod attrs_mod,
2321 bool copy_if_newer,
20effc67 2322 Attrs& attrs,
f67539c2
TL
2323 RGWObjCategory category,
2324 uint64_t olh_epoch,
2325 boost::optional<ceph::real_time> delete_at,
20effc67
TL
2326 std::string* version_id,
2327 std::string* tag,
2328 std::string* etag,
f67539c2 2329 void (*progress_cb)(off_t, void *),
20effc67
TL
2330 void* progress_data,
2331 const DoutPrefixProvider* dpp,
f67539c2
TL
2332 optional_yield y)
2333{
1e59de90 2334 return store->getRados()->copy_obj(*rados_ctx,
f67539c2
TL
2335 user->get_id(),
2336 info,
2337 source_zone,
1e59de90
TL
2338 dest_object->get_obj(),
2339 get_obj(),
2340 dest_bucket->get_info(),
2341 src_bucket->get_info(),
f67539c2
TL
2342 dest_placement,
2343 src_mtime,
2344 mtime,
2345 mod_ptr,
2346 unmod_ptr,
2347 high_precision_time,
2348 if_match,
2349 if_nomatch,
2350 static_cast<RGWRados::AttrsMod>(attrs_mod),
2351 copy_if_newer,
2352 attrs,
2353 category,
2354 olh_epoch,
2355 (delete_at ? *delete_at : real_time()),
2356 version_id,
2357 tag,
2358 etag,
2359 progress_cb,
20effc67
TL
2360 progress_data,
2361 dpp,
2362 y);
f67539c2
TL
2363}
2364
20effc67 2365int RadosObject::RadosReadOp::iterate(const DoutPrefixProvider* dpp, int64_t ofs, int64_t end, RGWGetDataCB* cb, optional_yield y)
f67539c2 2366{
20effc67 2367 return parent_op.iterate(dpp, ofs, end, cb, y);
f67539c2
TL
2368}
2369
1e59de90
TL
2370int RadosObject::swift_versioning_restore(bool& restored,
2371 const DoutPrefixProvider* dpp)
f67539c2 2372{
1e59de90
TL
2373 rgw_obj obj = get_obj();
2374 return store->getRados()->swift_versioning_restore(*rados_ctx,
f67539c2 2375 bucket->get_owner()->get_id(),
1e59de90
TL
2376 bucket->get_info(),
2377 obj,
f67539c2
TL
2378 restored,
2379 dpp);
2380}
2381
1e59de90 2382int RadosObject::swift_versioning_copy(const DoutPrefixProvider* dpp, optional_yield y)
f67539c2 2383{
1e59de90 2384 return store->getRados()->swift_versioning_copy(*rados_ctx,
f67539c2 2385 bucket->get_info().owner,
1e59de90
TL
2386 bucket->get_info(),
2387 get_obj(),
f67539c2
TL
2388 dpp,
2389 y);
2390}
2391
1e59de90
TL
2392int RadosMultipartUpload::cleanup_part_history(const DoutPrefixProvider* dpp,
2393 optional_yield y,
2394 RadosMultipartPart *part,
2395 list<rgw_obj_index_key>& remove_objs)
2396{
2397 cls_rgw_obj_chain chain;
2398 for (auto& ppfx : part->get_past_prefixes()) {
2399 rgw_obj past_obj;
2400 past_obj.init_ns(bucket->get_key(), ppfx + "." + std::to_string(part->info.num), mp_ns);
2401 rgw_obj_index_key past_key;
2402 past_obj.key.get_index_key(&past_key);
2403 // Remove past upload part objects from index, too.
2404 remove_objs.push_back(past_key);
2405
2406 RGWObjManifest manifest = part->get_manifest();
2407 manifest.set_prefix(ppfx);
2408 RGWObjManifest::obj_iterator miter = manifest.obj_begin(dpp);
2409 for (; miter != manifest.obj_end(dpp); ++miter) {
2410 rgw_raw_obj raw_part_obj = miter.get_location().get_raw_obj(store->getRados());
2411 cls_rgw_obj_key part_key(raw_part_obj.oid);
2412 chain.push_obj(raw_part_obj.pool.to_str(), part_key, raw_part_obj.loc);
2413 }
2414 }
2415 if (store->getRados()->get_gc() == nullptr) {
2416 // Delete objects inline if gc hasn't been initialised (in case when bypass gc is specified)
2417 store->getRados()->delete_objs_inline(dpp, chain, mp_obj.get_upload_id());
2418 } else {
2419 // use upload id as tag and do it synchronously
2420 auto [ret, leftover_chain] = store->getRados()->send_chain_to_gc(chain, mp_obj.get_upload_id());
2421 if (ret < 0 && leftover_chain) {
2422 ldpp_dout(dpp, 5) << __func__ << ": gc->send_chain() returned " << ret << dendl;
2423 if (ret == -ENOENT) {
2424 return -ERR_NO_SUCH_UPLOAD;
2425 }
2426 // Delete objects inline if send chain to gc fails
2427 store->getRados()->delete_objs_inline(dpp, *leftover_chain, mp_obj.get_upload_id());
2428 }
2429 }
2430 return 0;
2431}
2432
2433
2434int RadosMultipartUpload::abort(const DoutPrefixProvider *dpp, CephContext *cct)
f67539c2 2435{
20effc67
TL
2436 std::unique_ptr<rgw::sal::Object> meta_obj = get_meta_obj();
2437 meta_obj->set_in_extra_data(true);
2438 meta_obj->set_hash_source(mp_obj.get_key());
2439 cls_rgw_obj_chain chain;
2440 list<rgw_obj_index_key> remove_objs;
2441 bool truncated;
2442 int marker = 0;
f67539c2 2443 int ret;
20effc67
TL
2444 uint64_t parts_accounted_size = 0;
2445
2446 do {
2447 ret = list_parts(dpp, cct, 1000, marker, &marker, &truncated);
2448 if (ret < 0) {
2449 ldpp_dout(dpp, 20) << __func__ << ": RadosMultipartUpload::list_parts returned " <<
2450 ret << dendl;
2451 return (ret == -ENOENT) ? -ERR_NO_SUCH_UPLOAD : ret;
2452 }
2453
2454 for (auto part_it = parts.begin();
2455 part_it != parts.end();
2456 ++part_it) {
2457 RadosMultipartPart* obj_part = dynamic_cast<RadosMultipartPart*>(part_it->second.get());
2458 if (obj_part->info.manifest.empty()) {
2459 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(
2460 rgw_obj_key(obj_part->oid, std::string(), RGW_OBJ_NS_MULTIPART));
2461 obj->set_hash_source(mp_obj.get_key());
1e59de90 2462 ret = obj->delete_object(dpp, null_yield);
20effc67
TL
2463 if (ret < 0 && ret != -ENOENT)
2464 return ret;
2465 } else {
2466 auto target = meta_obj->get_obj();
2467 store->getRados()->update_gc_chain(dpp, target, obj_part->info.manifest, &chain);
2468 RGWObjManifest::obj_iterator oiter = obj_part->info.manifest.obj_begin(dpp);
2469 if (oiter != obj_part->info.manifest.obj_end(dpp)) {
2470 std::unique_ptr<rgw::sal::Object> head = bucket->get_object(rgw_obj_key());
1e59de90 2471 rgw_raw_obj raw_head = oiter.get_location().get_raw_obj(store->getRados());
20effc67
TL
2472 dynamic_cast<rgw::sal::RadosObject*>(head.get())->raw_obj_to_obj(raw_head);
2473
2474 rgw_obj_index_key key;
2475 head->get_key().get_index_key(&key);
2476 remove_objs.push_back(key);
1e59de90
TL
2477
2478 cleanup_part_history(dpp, null_yield, obj_part, remove_objs);
20effc67
TL
2479 }
2480 }
2481 parts_accounted_size += obj_part->info.accounted_size;
2482 }
2483 } while (truncated);
2484
2485 if (store->getRados()->get_gc() == nullptr) {
2486 //Delete objects inline if gc hasn't been initialised (in case when bypass gc is specified)
2487 store->getRados()->delete_objs_inline(dpp, chain, mp_obj.get_upload_id());
2488 } else {
2489 /* use upload id as tag and do it synchronously */
39ae355f
TL
2490 auto [ret, leftover_chain] = store->getRados()->send_chain_to_gc(chain, mp_obj.get_upload_id());
2491 if (ret < 0 && leftover_chain) {
20effc67
TL
2492 ldpp_dout(dpp, 5) << __func__ << ": gc->send_chain() returned " << ret << dendl;
2493 if (ret == -ENOENT) {
2494 return -ERR_NO_SUCH_UPLOAD;
2495 }
2496 //Delete objects inline if send chain to gc fails
39ae355f 2497 store->getRados()->delete_objs_inline(dpp, *leftover_chain, mp_obj.get_upload_id());
20effc67
TL
2498 }
2499 }
f67539c2 2500
1e59de90 2501 std::unique_ptr<rgw::sal::Object::DeleteOp> del_op = meta_obj->get_delete_op();
20effc67
TL
2502 del_op->params.bucket_owner = bucket->get_acl_owner();
2503 del_op->params.versioning_status = 0;
2504 if (!remove_objs.empty()) {
2505 del_op->params.remove_objs = &remove_objs;
2506 }
2507
2508 del_op->params.abortmp = true;
2509 del_op->params.parts_accounted_size = parts_accounted_size;
2510
2511 // and also remove the metadata obj
2512 ret = del_op->delete_obj(dpp, null_yield);
f67539c2 2513 if (ret < 0) {
20effc67
TL
2514 ldpp_dout(dpp, 20) << __func__ << ": del_op.delete_obj returned " <<
2515 ret << dendl;
f67539c2 2516 }
20effc67
TL
2517 return (ret == -ENOENT) ? -ERR_NO_SUCH_UPLOAD : ret;
2518}
f67539c2 2519
20effc67
TL
2520std::unique_ptr<rgw::sal::Object> RadosMultipartUpload::get_meta_obj()
2521{
2522 return bucket->get_object(rgw_obj_key(get_meta(), string(), mp_ns));
f67539c2
TL
2523}
2524
1e59de90 2525int RadosMultipartUpload::init(const DoutPrefixProvider *dpp, optional_yield y, ACLOwner& owner, rgw_placement_rule& dest_placement, rgw::sal::Attrs& attrs)
f67539c2 2526{
20effc67
TL
2527 int ret;
2528 std::string oid = mp_obj.get_key();
1e59de90 2529 RGWObjectCtx obj_ctx(store);
f67539c2 2530
20effc67
TL
2531 do {
2532 char buf[33];
2533 string tmp_obj_name;
2534 std::unique_ptr<rgw::sal::Object> obj;
2535 gen_rand_alphanumeric(store->ctx(), buf, sizeof(buf) - 1);
2536 std::string upload_id = MULTIPART_UPLOAD_ID_PREFIX; /* v2 upload id */
2537 upload_id.append(buf);
2538
2539 mp_obj.init(oid, upload_id);
2540 tmp_obj_name = mp_obj.get_meta();
2541
2542 obj = bucket->get_object(rgw_obj_key(tmp_obj_name, string(), mp_ns));
2543 // the meta object will be indexed with 0 size, we c
2544 obj->set_in_extra_data(true);
2545 obj->set_hash_source(oid);
2546
2547 RGWRados::Object op_target(store->getRados(),
2548 obj->get_bucket()->get_info(),
1e59de90 2549 obj_ctx, obj->get_obj());
20effc67
TL
2550 RGWRados::Object::Write obj_op(&op_target);
2551
2552 op_target.set_versioning_disabled(true); /* no versioning for multipart meta */
2553 obj_op.meta.owner = owner.get_id();
2554 obj_op.meta.category = RGWObjCategory::MultiMeta;
2555 obj_op.meta.flags = PUT_OBJ_CREATE_EXCL;
2556 obj_op.meta.mtime = &mtime;
2557
2558 multipart_upload_info upload_info;
2559 upload_info.dest_placement = dest_placement;
2560
2561 bufferlist bl;
2562 encode(upload_info, bl);
2563 obj_op.meta.data = &bl;
2564
2565 ret = obj_op.write_meta(dpp, bl.length(), 0, attrs, y);
2566 } while (ret == -EEXIST);
f67539c2 2567
20effc67 2568 return ret;
f67539c2
TL
2569}
2570
20effc67
TL
2571int RadosMultipartUpload::list_parts(const DoutPrefixProvider *dpp, CephContext *cct,
2572 int num_parts, int marker,
2573 int *next_marker, bool *truncated,
2574 bool assume_unsorted)
f67539c2 2575{
20effc67
TL
2576 map<string, bufferlist> parts_map;
2577 map<string, bufferlist>::iterator iter;
f67539c2 2578
20effc67
TL
2579 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(
2580 rgw_obj_key(get_meta(), std::string(), RGW_OBJ_NS_MULTIPART));
2581 obj->set_in_extra_data(true);
f67539c2 2582
20effc67 2583 bool sorted_omap = is_v2_upload_id(get_upload_id()) && !assume_unsorted;
f67539c2 2584
20effc67
TL
2585 parts.clear();
2586
2587 int ret;
2588 if (sorted_omap) {
2589 string p;
2590 p = "part.";
2591 char buf[32];
2592
2593 snprintf(buf, sizeof(buf), "%08d", marker);
2594 p.append(buf);
2595
2596 ret = obj->omap_get_vals(dpp, p, num_parts + 1, &parts_map,
2597 nullptr, null_yield);
2598 } else {
2599 ret = obj->omap_get_all(dpp, &parts_map, null_yield);
f67539c2 2600 }
20effc67
TL
2601 if (ret < 0) {
2602 return ret;
f67539c2 2603 }
f67539c2 2604
20effc67
TL
2605 int i;
2606 int last_num = 0;
f67539c2 2607
20effc67 2608 uint32_t expected_next = marker + 1;
f67539c2 2609
20effc67
TL
2610 for (i = 0, iter = parts_map.begin();
2611 (i < num_parts || !sorted_omap) && iter != parts_map.end();
2612 ++iter, ++i) {
2613 bufferlist& bl = iter->second;
2614 auto bli = bl.cbegin();
2615 std::unique_ptr<RadosMultipartPart> part = std::make_unique<RadosMultipartPart>();
2616 try {
2617 decode(part->info, bli);
2618 } catch (buffer::error& err) {
2619 ldpp_dout(dpp, 0) << "ERROR: could not part info, caught buffer::error" <<
2620 dendl;
2621 return -EIO;
2622 }
2623 if (sorted_omap) {
2624 if (part->info.num != expected_next) {
2625 /* ouch, we expected a specific part num here, but we got a
2626 * different one. Either a part is missing, or it could be a
2627 * case of mixed rgw versions working on the same upload,
2628 * where one gateway doesn't support correctly sorted omap
2629 * keys for multipart upload just assume data is unsorted.
2630 */
2631 return list_parts(dpp, cct, num_parts, marker, next_marker, truncated, true);
2632 }
2633 expected_next++;
2634 }
2635 if (sorted_omap ||
2636 (int)part->info.num > marker) {
2637 last_num = part->info.num;
2638 parts[part->info.num] = std::move(part);
2639 }
f67539c2 2640 }
f67539c2 2641
20effc67
TL
2642 if (sorted_omap) {
2643 if (truncated) {
2644 *truncated = (iter != parts_map.end());
2645 }
2646 } else {
2647 /* rebuild a map with only num_parts entries */
2648 std::map<uint32_t, std::unique_ptr<MultipartPart>> new_parts;
2649 std::map<uint32_t, std::unique_ptr<MultipartPart>>::iterator piter;
2650 for (i = 0, piter = parts.begin();
2651 i < num_parts && piter != parts.end();
2652 ++i, ++piter) {
2653 last_num = piter->first;
2654 new_parts[piter->first] = std::move(piter->second);
2655 }
f67539c2 2656
20effc67
TL
2657 if (truncated) {
2658 *truncated = (piter != parts.end());
2659 }
f67539c2 2660
20effc67 2661 parts.swap(new_parts);
f67539c2 2662 }
f67539c2 2663
20effc67
TL
2664 if (next_marker) {
2665 *next_marker = last_num;
f67539c2
TL
2666 }
2667
2668 return 0;
2669}
2670
20effc67
TL
2671int RadosMultipartUpload::complete(const DoutPrefixProvider *dpp,
2672 optional_yield y, CephContext* cct,
2673 map<int, string>& part_etags,
2674 list<rgw_obj_index_key>& remove_objs,
2675 uint64_t& accounted_size, bool& compressed,
2676 RGWCompressionInfo& cs_info, off_t& ofs,
2677 std::string& tag, ACLOwner& owner,
2678 uint64_t olh_epoch,
1e59de90 2679 rgw::sal::Object* target_obj)
20effc67
TL
2680{
2681 char final_etag[CEPH_CRYPTO_MD5_DIGESTSIZE];
2682 char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16];
2683 std::string etag;
2684 bufferlist etag_bl;
2685 MD5 hash;
2686 // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes
2687 hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
2688 bool truncated;
2689 int ret;
f67539c2 2690
20effc67
TL
2691 int total_parts = 0;
2692 int handled_parts = 0;
2693 int max_parts = 1000;
2694 int marker = 0;
2695 uint64_t min_part_size = cct->_conf->rgw_multipart_min_part_size;
2696 auto etags_iter = part_etags.begin();
2697 rgw::sal::Attrs attrs = target_obj->get_attrs();
f67539c2 2698
20effc67
TL
2699 do {
2700 ret = list_parts(dpp, cct, max_parts, marker, &marker, &truncated);
2701 if (ret == -ENOENT) {
2702 ret = -ERR_NO_SUCH_UPLOAD;
2703 }
2704 if (ret < 0)
2705 return ret;
f67539c2 2706
20effc67
TL
2707 total_parts += parts.size();
2708 if (!truncated && total_parts != (int)part_etags.size()) {
2709 ldpp_dout(dpp, 0) << "NOTICE: total parts mismatch: have: " << total_parts
2710 << " expected: " << part_etags.size() << dendl;
2711 ret = -ERR_INVALID_PART;
2712 return ret;
2713 }
f67539c2 2714
20effc67
TL
2715 for (auto obj_iter = parts.begin(); etags_iter != part_etags.end() && obj_iter != parts.end(); ++etags_iter, ++obj_iter, ++handled_parts) {
2716 RadosMultipartPart* part = dynamic_cast<rgw::sal::RadosMultipartPart*>(obj_iter->second.get());
2717 uint64_t part_size = part->get_size();
2718 if (handled_parts < (int)part_etags.size() - 1 &&
2719 part_size < min_part_size) {
2720 ret = -ERR_TOO_SMALL;
2721 return ret;
2722 }
f67539c2 2723
20effc67
TL
2724 char petag[CEPH_CRYPTO_MD5_DIGESTSIZE];
2725 if (etags_iter->first != (int)obj_iter->first) {
2726 ldpp_dout(dpp, 0) << "NOTICE: parts num mismatch: next requested: "
2727 << etags_iter->first << " next uploaded: "
2728 << obj_iter->first << dendl;
2729 ret = -ERR_INVALID_PART;
2730 return ret;
2731 }
2732 string part_etag = rgw_string_unquote(etags_iter->second);
2733 if (part_etag.compare(part->get_etag()) != 0) {
2734 ldpp_dout(dpp, 0) << "NOTICE: etag mismatch: part: " << etags_iter->first
2735 << " etag: " << etags_iter->second << dendl;
2736 ret = -ERR_INVALID_PART;
2737 return ret;
2738 }
f67539c2 2739
20effc67
TL
2740 hex_to_buf(part->get_etag().c_str(), petag,
2741 CEPH_CRYPTO_MD5_DIGESTSIZE);
2742 hash.Update((const unsigned char *)petag, sizeof(petag));
f67539c2 2743
20effc67 2744 RGWUploadPartInfo& obj_part = part->info;
f67539c2 2745
20effc67
TL
2746 /* update manifest for part */
2747 string oid = mp_obj.get_part(part->info.num);
2748 rgw_obj src_obj;
2749 src_obj.init_ns(bucket->get_key(), oid, mp_ns);
f67539c2 2750
20effc67
TL
2751 if (obj_part.manifest.empty()) {
2752 ldpp_dout(dpp, 0) << "ERROR: empty manifest for object part: obj="
2753 << src_obj << dendl;
2754 ret = -ERR_INVALID_PART;
2755 return ret;
2756 } else {
1e59de90
TL
2757 manifest.append(dpp, obj_part.manifest, store->svc()->zone->get_zonegroup(), store->svc()->zone->get_zone_params());
2758 auto manifest_prefix = part->info.manifest.get_prefix();
2759 if (not manifest_prefix.empty()) {
2760 // It has an explicit prefix. Override the default one.
2761 src_obj.init_ns(bucket->get_key(), manifest_prefix + "." + std::to_string(part->info.num), mp_ns);
2762 }
20effc67 2763 }
f67539c2 2764
20effc67
TL
2765 bool part_compressed = (obj_part.cs_info.compression_type != "none");
2766 if ((handled_parts > 0) &&
2767 ((part_compressed != compressed) ||
2768 (cs_info.compression_type != obj_part.cs_info.compression_type))) {
2769 ldpp_dout(dpp, 0) << "ERROR: compression type was changed during multipart upload ("
2770 << cs_info.compression_type << ">>" << obj_part.cs_info.compression_type << ")" << dendl;
2771 ret = -ERR_INVALID_PART;
2772 return ret;
2773 }
2774
2775 if (part_compressed) {
2776 int64_t new_ofs; // offset in compression data for new part
2777 if (cs_info.blocks.size() > 0)
2778 new_ofs = cs_info.blocks.back().new_ofs + cs_info.blocks.back().len;
2779 else
2780 new_ofs = 0;
2781 for (const auto& block : obj_part.cs_info.blocks) {
2782 compression_block cb;
2783 cb.old_ofs = block.old_ofs + cs_info.orig_size;
2784 cb.new_ofs = new_ofs;
2785 cb.len = block.len;
2786 cs_info.blocks.push_back(cb);
2787 new_ofs = cb.new_ofs + cb.len;
2788 }
2789 if (!compressed)
2790 cs_info.compression_type = obj_part.cs_info.compression_type;
2791 cs_info.orig_size += obj_part.cs_info.orig_size;
2792 compressed = true;
2793 }
f67539c2 2794
20effc67
TL
2795 rgw_obj_index_key remove_key;
2796 src_obj.key.get_index_key(&remove_key);
f67539c2 2797
20effc67
TL
2798 remove_objs.push_back(remove_key);
2799
1e59de90
TL
2800 cleanup_part_history(dpp, y, part, remove_objs);
2801
20effc67
TL
2802 ofs += obj_part.size;
2803 accounted_size += obj_part.accounted_size;
f67539c2 2804 }
20effc67
TL
2805 } while (truncated);
2806 hash.Final((unsigned char *)final_etag);
2807
2808 buf_to_hex((unsigned char *)final_etag, sizeof(final_etag), final_etag_str);
2809 snprintf(&final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2],
2810 sizeof(final_etag_str) - CEPH_CRYPTO_MD5_DIGESTSIZE * 2,
2811 "-%lld", (long long)part_etags.size());
2812 etag = final_etag_str;
2813 ldpp_dout(dpp, 10) << "calculated etag: " << etag << dendl;
2814
2815 etag_bl.append(etag);
2816
2817 attrs[RGW_ATTR_ETAG] = etag_bl;
2818
2819 if (compressed) {
2820 // write compression attribute to full object
2821 bufferlist tmp;
2822 encode(cs_info, tmp);
2823 attrs[RGW_ATTR_COMPRESSION] = tmp;
f67539c2
TL
2824 }
2825
1e59de90 2826 target_obj->set_atomic();
20effc67
TL
2827
2828 RGWRados::Object op_target(store->getRados(),
2829 target_obj->get_bucket()->get_info(),
1e59de90
TL
2830 dynamic_cast<RadosObject*>(target_obj)->get_ctx(),
2831 target_obj->get_obj());
20effc67
TL
2832 RGWRados::Object::Write obj_op(&op_target);
2833
2834 obj_op.meta.manifest = &manifest;
2835 obj_op.meta.remove_objs = &remove_objs;
2836
2837 obj_op.meta.ptag = &tag; /* use req_id as operation tag */
2838 obj_op.meta.owner = owner.get_id();
2839 obj_op.meta.flags = PUT_OBJ_CREATE;
2840 obj_op.meta.modify_tail = true;
2841 obj_op.meta.completeMultipart = true;
2842 obj_op.meta.olh_epoch = olh_epoch;
2843
2844 ret = obj_op.write_meta(dpp, ofs, accounted_size, attrs, y);
2845 if (ret < 0)
2846 return ret;
2847
2848 return ret;
2849}
2850
1e59de90 2851int RadosMultipartUpload::get_info(const DoutPrefixProvider *dpp, optional_yield y, rgw_placement_rule** rule, rgw::sal::Attrs* attrs)
20effc67
TL
2852{
2853 if (!rule && !attrs) {
2854 return 0;
f67539c2
TL
2855 }
2856
20effc67
TL
2857 if (rule) {
2858 if (!placement.empty()) {
2859 *rule = &placement;
2860 if (!attrs) {
2861 /* Don't need attrs, done */
2862 return 0;
2863 }
2864 } else {
2865 *rule = nullptr;
f67539c2 2866 }
20effc67 2867 }
f67539c2 2868
20effc67
TL
2869 /* We need either attributes or placement, so we need a read */
2870 std::unique_ptr<rgw::sal::Object> meta_obj;
2871 meta_obj = get_meta_obj();
2872 meta_obj->set_in_extra_data(true);
2873
2874 multipart_upload_info upload_info;
2875 bufferlist headbl;
2876
2877 /* Read the obj head which contains the multipart_upload_info */
1e59de90
TL
2878 std::unique_ptr<rgw::sal::Object::ReadOp> read_op = meta_obj->get_read_op();
2879 meta_obj->set_prefetch_data();
20effc67
TL
2880
2881 int ret = read_op->prepare(y, dpp);
2882 if (ret < 0) {
2883 if (ret == -ENOENT) {
2884 return -ERR_NO_SUCH_UPLOAD;
f67539c2 2885 }
20effc67 2886 return ret;
f67539c2
TL
2887 }
2888
20effc67 2889 extract_span_context(meta_obj->get_attrs(), trace_ctx);
f67539c2 2890
20effc67
TL
2891 if (attrs) {
2892 /* Attrs are filled in by prepare */
2893 *attrs = meta_obj->get_attrs();
2894 if (!rule || *rule != nullptr) {
2895 /* placement was cached; don't actually read */
2896 return 0;
2897 }
2898 }
f67539c2 2899
20effc67
TL
2900 /* Now read the placement from the head */
2901 ret = read_op->read(0, store->ctx()->_conf->rgw_max_chunk_size, headbl, y, dpp);
2902 if (ret < 0) {
2903 if (ret == -ENOENT) {
2904 return -ERR_NO_SUCH_UPLOAD;
2905 }
2906 return ret;
2907 }
f67539c2 2908
20effc67
TL
2909 if (headbl.length() <= 0) {
2910 return -ERR_NO_SUCH_UPLOAD;
2911 }
f67539c2 2912
20effc67
TL
2913 /* Decode multipart_upload_info */
2914 auto hiter = headbl.cbegin();
2915 try {
2916 decode(upload_info, hiter);
2917 } catch (buffer::error& err) {
2918 ldpp_dout(dpp, 0) << "ERROR: failed to decode multipart upload info" << dendl;
2919 return -EIO;
2920 }
2921 placement = upload_info.dest_placement;
2922 *rule = &placement;
f67539c2 2923
20effc67 2924 return 0;
f67539c2
TL
2925}
2926
20effc67
TL
2927std::unique_ptr<Writer> RadosMultipartUpload::get_writer(
2928 const DoutPrefixProvider *dpp,
2929 optional_yield y,
1e59de90
TL
2930 rgw::sal::Object* obj,
2931 const rgw_user& owner,
20effc67
TL
2932 const rgw_placement_rule *ptail_placement_rule,
2933 uint64_t part_num,
2934 const std::string& part_num_str)
f67539c2 2935{
1e59de90
TL
2936 RGWBucketInfo& bucket_info = obj->get_bucket()->get_info();
2937 RGWObjectCtx& obj_ctx = static_cast<RadosObject*>(obj)->get_ctx();
20effc67 2938 auto aio = rgw::make_throttle(store->ctx()->_conf->rgw_put_obj_min_window_size, y);
1e59de90
TL
2939 return std::make_unique<RadosMultipartWriter>(dpp, y, get_upload_id(),
2940 bucket_info, obj_ctx,
2941 obj->get_obj(), store, std::move(aio), owner,
2942 ptail_placement_rule, part_num, part_num_str);
f67539c2
TL
2943}
2944
20effc67 2945MPRadosSerializer::MPRadosSerializer(const DoutPrefixProvider *dpp, RadosStore* store, RadosObject* obj, const std::string& lock_name) :
f67539c2
TL
2946 lock(lock_name)
2947{
2948 rgw_pool meta_pool;
2949 rgw_raw_obj raw_obj;
2950
2951 obj->get_raw_obj(&raw_obj);
2952 oid = raw_obj.oid;
2953 store->getRados()->get_obj_data_pool(obj->get_bucket()->get_placement_rule(),
2954 obj->get_obj(), &meta_pool);
05a536ef 2955 store->getRados()->open_pool_ctx(dpp, meta_pool, ioctx, true, true);
f67539c2
TL
2956}
2957
b3b6e05e 2958int MPRadosSerializer::try_lock(const DoutPrefixProvider *dpp, utime_t dur, optional_yield y)
f67539c2
TL
2959{
2960 op.assert_exists();
2961 lock.set_duration(dur);
2962 lock.lock_exclusive(&op);
b3b6e05e 2963 int ret = rgw_rados_operate(dpp, ioctx, oid, &op, y);
f67539c2
TL
2964 if (! ret) {
2965 locked = true;
2966 }
2967 return ret;
2968}
2969
20effc67 2970LCRadosSerializer::LCRadosSerializer(RadosStore* store, const std::string& _oid, const std::string& lock_name, const std::string& cookie) :
1e59de90
TL
2971 StoreLCSerializer(_oid),
2972 lock(lock_name)
f67539c2
TL
2973{
2974 ioctx = &store->getRados()->lc_pool_ctx;
2975 lock.set_cookie(cookie);
2976}
2977
b3b6e05e 2978int LCRadosSerializer::try_lock(const DoutPrefixProvider *dpp, utime_t dur, optional_yield y)
f67539c2
TL
2979{
2980 lock.set_duration(dur);
2981 return lock.lock_exclusive(ioctx, oid);
2982}
2983
20effc67 2984int RadosLifecycle::get_entry(const std::string& oid, const std::string& marker,
1e59de90 2985 std::unique_ptr<LCEntry>* entry)
f67539c2
TL
2986{
2987 cls_rgw_lc_entry cls_entry;
2988 int ret = cls_rgw_lc_get_entry(*store->getRados()->get_lc_pool_ctx(), oid, marker, cls_entry);
1e59de90
TL
2989 if (ret)
2990 return ret;
f67539c2 2991
1e59de90
TL
2992 LCEntry* e;
2993 e = new StoreLCEntry(cls_entry.bucket, cls_entry.start_time, cls_entry.status);
2994 if (!e)
2995 return -ENOMEM;
f67539c2 2996
1e59de90
TL
2997 entry->reset(e);
2998 return 0;
f67539c2
TL
2999}
3000
1e59de90
TL
3001int RadosLifecycle::get_next_entry(const std::string& oid, const std::string& marker,
3002 std::unique_ptr<LCEntry>* entry)
f67539c2
TL
3003{
3004 cls_rgw_lc_entry cls_entry;
3005 int ret = cls_rgw_lc_get_next_entry(*store->getRados()->get_lc_pool_ctx(), oid, marker,
3006 cls_entry);
3007
1e59de90
TL
3008 if (ret)
3009 return ret;
3010
3011 LCEntry* e;
3012 e = new StoreLCEntry(cls_entry.bucket, cls_entry.start_time, cls_entry.status);
3013 if (!e)
3014 return -ENOMEM;
f67539c2 3015
1e59de90
TL
3016 entry->reset(e);
3017 return 0;
f67539c2
TL
3018}
3019
1e59de90 3020int RadosLifecycle::set_entry(const std::string& oid, LCEntry& entry)
f67539c2
TL
3021{
3022 cls_rgw_lc_entry cls_entry;
3023
1e59de90
TL
3024 cls_entry.bucket = entry.get_bucket();
3025 cls_entry.start_time = entry.get_start_time();
3026 cls_entry.status = entry.get_status();
f67539c2
TL
3027
3028 return cls_rgw_lc_set_entry(*store->getRados()->get_lc_pool_ctx(), oid, cls_entry);
3029}
3030
20effc67 3031int RadosLifecycle::list_entries(const std::string& oid, const std::string& marker,
1e59de90 3032 uint32_t max_entries, std::vector<std::unique_ptr<LCEntry>>& entries)
f67539c2
TL
3033{
3034 entries.clear();
3035
3036 vector<cls_rgw_lc_entry> cls_entries;
3037 int ret = cls_rgw_lc_list(*store->getRados()->get_lc_pool_ctx(), oid, marker, max_entries, cls_entries);
3038
3039 if (ret < 0)
3040 return ret;
3041
3042 for (auto& entry : cls_entries) {
1e59de90
TL
3043 entries.push_back(std::make_unique<StoreLCEntry>(entry.bucket, oid,
3044 entry.start_time, entry.status));
f67539c2
TL
3045 }
3046
3047 return ret;
3048}
3049
1e59de90 3050int RadosLifecycle::rm_entry(const std::string& oid, LCEntry& entry)
f67539c2
TL
3051{
3052 cls_rgw_lc_entry cls_entry;
3053
1e59de90
TL
3054 cls_entry.bucket = entry.get_bucket();
3055 cls_entry.start_time = entry.get_start_time();
3056 cls_entry.status = entry.get_status();
f67539c2
TL
3057
3058 return cls_rgw_lc_rm_entry(*store->getRados()->get_lc_pool_ctx(), oid, cls_entry);
3059}
3060
1e59de90 3061int RadosLifecycle::get_head(const std::string& oid, std::unique_ptr<LCHead>* head)
f67539c2
TL
3062{
3063 cls_rgw_lc_obj_head cls_head;
3064 int ret = cls_rgw_lc_get_head(*store->getRados()->get_lc_pool_ctx(), oid, cls_head);
1e59de90
TL
3065 if (ret)
3066 return ret;
f67539c2 3067
1e59de90
TL
3068 LCHead* h;
3069 h = new StoreLCHead(cls_head.start_date, cls_head.shard_rollover_date, cls_head.marker);
3070 if (!h)
3071 return -ENOMEM;
f67539c2 3072
1e59de90
TL
3073 head->reset(h);
3074 return 0;
f67539c2
TL
3075}
3076
1e59de90 3077int RadosLifecycle::put_head(const std::string& oid, LCHead& head)
f67539c2
TL
3078{
3079 cls_rgw_lc_obj_head cls_head;
3080
1e59de90
TL
3081 cls_head.marker = head.get_marker();
3082 cls_head.start_date = head.get_start_date();
3083 cls_head.shard_rollover_date = head.get_shard_rollover_date();
f67539c2
TL
3084
3085 return cls_rgw_lc_put_head(*store->getRados()->get_lc_pool_ctx(), oid, cls_head);
3086}
3087
1e59de90
TL
3088std::unique_ptr<LCSerializer> RadosLifecycle::get_serializer(const std::string& lock_name,
3089 const std::string& oid,
3090 const std::string& cookie)
f67539c2 3091{
1e59de90 3092 return std::make_unique<LCRadosSerializer>(store, oid, lock_name, cookie);
f67539c2
TL
3093}
3094
20effc67
TL
3095int RadosNotification::publish_reserve(const DoutPrefixProvider *dpp, RGWObjTags* obj_tags)
3096{
3097 return rgw::notify::publish_reserve(dpp, event_type, res, obj_tags);
3098}
3099
3100int RadosNotification::publish_commit(const DoutPrefixProvider* dpp, uint64_t size,
3101 const ceph::real_time& mtime, const std::string& etag, const std::string& version)
3102{
3103 return rgw::notify::publish_commit(obj, size, mtime, etag, version, event_type, res, dpp);
3104}
3105
3106int RadosAtomicWriter::prepare(optional_yield y)
3107{
3108 return processor.prepare(y);
3109}
3110
3111int RadosAtomicWriter::process(bufferlist&& data, uint64_t offset)
3112{
3113 return processor.process(std::move(data), offset);
3114}
3115
3116int RadosAtomicWriter::complete(size_t accounted_size, const std::string& etag,
3117 ceph::real_time *mtime, ceph::real_time set_mtime,
3118 std::map<std::string, bufferlist>& attrs,
3119 ceph::real_time delete_at,
3120 const char *if_match, const char *if_nomatch,
3121 const std::string *user_data,
3122 rgw_zone_set *zones_trace, bool *canceled,
3123 optional_yield y)
3124{
3125 return processor.complete(accounted_size, etag, mtime, set_mtime, attrs, delete_at,
3126 if_match, if_nomatch, user_data, zones_trace, canceled, y);
3127}
3128
3129int RadosAppendWriter::prepare(optional_yield y)
3130{
3131 return processor.prepare(y);
3132}
3133
3134int RadosAppendWriter::process(bufferlist&& data, uint64_t offset)
3135{
3136 return processor.process(std::move(data), offset);
3137}
3138
3139int RadosAppendWriter::complete(size_t accounted_size, const std::string& etag,
3140 ceph::real_time *mtime, ceph::real_time set_mtime,
3141 std::map<std::string, bufferlist>& attrs,
3142 ceph::real_time delete_at,
3143 const char *if_match, const char *if_nomatch,
3144 const std::string *user_data,
3145 rgw_zone_set *zones_trace, bool *canceled,
3146 optional_yield y)
3147{
3148 return processor.complete(accounted_size, etag, mtime, set_mtime, attrs, delete_at,
3149 if_match, if_nomatch, user_data, zones_trace, canceled, y);
3150}
3151
3152int RadosMultipartWriter::prepare(optional_yield y)
3153{
3154 return processor.prepare(y);
3155}
3156
3157int RadosMultipartWriter::process(bufferlist&& data, uint64_t offset)
3158{
3159 return processor.process(std::move(data), offset);
3160}
3161
3162int RadosMultipartWriter::complete(size_t accounted_size, const std::string& etag,
3163 ceph::real_time *mtime, ceph::real_time set_mtime,
3164 std::map<std::string, bufferlist>& attrs,
3165 ceph::real_time delete_at,
3166 const char *if_match, const char *if_nomatch,
3167 const std::string *user_data,
3168 rgw_zone_set *zones_trace, bool *canceled,
3169 optional_yield y)
3170{
3171 return processor.complete(accounted_size, etag, mtime, set_mtime, attrs, delete_at,
3172 if_match, if_nomatch, user_data, zones_trace, canceled, y);
3173}
3174
1e59de90 3175const std::string& RadosZoneGroup::get_endpoint() const
20effc67 3176{
1e59de90
TL
3177 if (!group.endpoints.empty()) {
3178 return group.endpoints.front();
3179 } else {
3180 // use zonegroup's master zone endpoints
3181 auto z = group.zones.find(group.master_zone);
3182 if (z != group.zones.end() && !z->second.endpoints.empty()) {
3183 return z->second.endpoints.front();
3184 }
3185 }
3186 return empty;
20effc67
TL
3187}
3188
1e59de90 3189bool RadosZoneGroup::placement_target_exists(std::string& target) const
20effc67 3190{
1e59de90 3191 return !!group.placement_targets.count(target);
20effc67
TL
3192}
3193
aee94f69 3194void RadosZoneGroup::get_placement_target_names(std::set<std::string>& names) const
20effc67 3195{
1e59de90
TL
3196 for (const auto& target : group.placement_targets) {
3197 names.emplace(target.second.name);
3198 }
20effc67
TL
3199}
3200
1e59de90
TL
3201int RadosZoneGroup::get_placement_tier(const rgw_placement_rule& rule,
3202 std::unique_ptr<PlacementTier>* tier)
20effc67 3203{
1e59de90
TL
3204 std::map<std::string, RGWZoneGroupPlacementTarget>::const_iterator titer;
3205 titer = group.placement_targets.find(rule.name);
3206 if (titer == group.placement_targets.end()) {
3207 return -ENOENT;
3208 }
3209
3210 const auto& target_rule = titer->second;
3211 std::map<std::string, RGWZoneGroupPlacementTier>::const_iterator ttier;
3212 ttier = target_rule.tier_targets.find(rule.storage_class);
3213 if (ttier == target_rule.tier_targets.end()) {
3214 // not found
3215 return -ENOENT;
3216 }
3217
3218 PlacementTier* t;
3219 t = new RadosPlacementTier(store, ttier->second);
3220 if (!t)
3221 return -ENOMEM;
3222
3223 tier->reset(t);
3224 return 0;
20effc67
TL
3225}
3226
1e59de90 3227int RadosZoneGroup::get_zone_by_id(const std::string& id, std::unique_ptr<Zone>* zone)
20effc67 3228{
1e59de90
TL
3229 RGWZone* rz = store->svc()->zone->find_zone(id);
3230 if (!rz)
3231 return -ENOENT;
3232
3233 Zone* z = new RadosZone(store, clone(), *rz);
3234 zone->reset(z);
3235 return 0;
3236}
3237
3238int RadosZoneGroup::get_zone_by_name(const std::string& name, std::unique_ptr<Zone>* zone)
3239{
3240 rgw_zone_id id;
3241 int ret = store->svc()->zone->find_zone_id_by_name(name, &id);
3242 if (ret < 0)
3243 return ret;
3244
3245 RGWZone* rz = store->svc()->zone->find_zone(id.id);
3246 if (!rz)
3247 return -ENOENT;
3248
3249 Zone* z = new RadosZone(store, clone(), *rz);
3250 zone->reset(z);
3251 return 0;
3252}
3253
3254int RadosZoneGroup::list_zones(std::list<std::string>& zone_ids)
3255{
3256 for (const auto& entry : group.zones)
3257 {
3258 zone_ids.push_back(entry.second.id);
3259 }
3260 return 0;
3261}
3262
3263std::unique_ptr<Zone> RadosZone::clone()
3264{
3265 if (local_zone)
3266 return std::make_unique<RadosZone>(store, group->clone());
3267
3268 return std::make_unique<RadosZone>(store, group->clone(), rgw_zone);
3269}
3270
3271const std::string& RadosZone::get_id()
3272{
3273 if (local_zone)
3274 return store->svc()->zone->zone_id().id;
3275
3276 return rgw_zone.id;
20effc67
TL
3277}
3278
3279const std::string& RadosZone::get_name() const
3280{
1e59de90
TL
3281 if (local_zone)
3282 return store->svc()->zone->zone_name();
3283
3284 return rgw_zone.name;
20effc67
TL
3285}
3286
3287bool RadosZone::is_writeable()
3288{
1e59de90
TL
3289 if (local_zone)
3290 return store->svc()->zone->zone_is_writeable();
3291
3292 return !rgw_zone.read_only;
20effc67
TL
3293}
3294
3295bool RadosZone::get_redirect_endpoint(std::string* endpoint)
3296{
1e59de90
TL
3297 if (local_zone)
3298 return store->svc()->zone->get_redirect_zone_endpoint(endpoint);
3299
3300 endpoint = &rgw_zone.redirect_zone;
3301 return true;
20effc67
TL
3302}
3303
3304bool RadosZone::has_zonegroup_api(const std::string& api) const
3305{
3306 return store->svc()->zone->has_zonegroup_api(api);
3307}
3308
3309const std::string& RadosZone::get_current_period_id()
3310{
3311 return store->svc()->zone->get_current_period_id();
3312}
f67539c2 3313
1e59de90 3314const RGWAccessKey& RadosZone::get_system_key()
f67539c2 3315{
1e59de90
TL
3316 return store->svc()->zone->get_zone_params().system_key;
3317}
3318
3319const std::string& RadosZone::get_realm_name()
3320{
3321 return store->svc()->zone->get_realm().get_name();
3322}
3323
3324const std::string& RadosZone::get_realm_id()
3325{
3326 return store->svc()->zone->get_realm().get_id();
3327}
3328
3329const std::string_view RadosZone::get_tier_type()
3330{
3331 if (local_zone)
3332 return store->svc()->zone->get_zone().tier_type;
3333
3334 return rgw_zone.id;
3335}
3336
3337RGWBucketSyncPolicyHandlerRef RadosZone::get_sync_policy_handler()
3338{
3339 return store->svc()->zone->get_sync_policy_handler(get_id());
3340}
3341
3342RadosLuaManager::RadosLuaManager(RadosStore* _s) :
3343 store(_s),
3344 pool((store->svc() && store->svc()->zone) ? store->svc()->zone->get_zone_params().log_pool : rgw_pool())
3345{ }
3346
3347int RadosLuaManager::get_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, std::string& script)
3348{
3349 if (pool.empty()) {
3350 ldpp_dout(dpp, 10) << "WARNING: missing pool when reading lua script " << dendl;
3351 return 0;
3352 }
20effc67 3353 bufferlist bl;
f67539c2 3354
1e59de90 3355 int r = rgw_get_system_obj(store->svc()->sysobj, pool, key, bl, nullptr, nullptr, y, dpp);
20effc67
TL
3356 if (r < 0) {
3357 return r;
3358 }
f67539c2 3359
20effc67
TL
3360 auto iter = bl.cbegin();
3361 try {
3362 ceph::decode(script, iter);
3363 } catch (buffer::error& err) {
3364 return -EIO;
f67539c2
TL
3365 }
3366
20effc67
TL
3367 return 0;
3368}
3369
1e59de90 3370int RadosLuaManager::put_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, const std::string& script)
20effc67 3371{
1e59de90
TL
3372 if (pool.empty()) {
3373 ldpp_dout(dpp, 10) << "WARNING: missing pool when writing lua script " << dendl;
3374 return 0;
3375 }
20effc67
TL
3376 bufferlist bl;
3377 ceph::encode(script, bl);
3378
1e59de90 3379 int r = rgw_put_system_obj(dpp, store->svc()->sysobj, pool, key, bl, false, nullptr, real_time(), y);
20effc67
TL
3380 if (r < 0) {
3381 return r;
3382 }
3383
3384 return 0;
3385}
3386
1e59de90 3387int RadosLuaManager::del_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key)
20effc67 3388{
1e59de90
TL
3389 if (pool.empty()) {
3390 ldpp_dout(dpp, 10) << "WARNING: missing pool when deleting lua script " << dendl;
3391 return 0;
3392 }
20effc67
TL
3393 int r = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, key, nullptr, y);
3394 if (r < 0 && r != -ENOENT) {
3395 return r;
3396 }
3397
3398 return 0;
3399}
3400
1e59de90
TL
3401const std::string PACKAGE_LIST_OBJECT_NAME = "lua_package_allowlist";
3402
3403int RadosLuaManager::add_package(const DoutPrefixProvider *dpp, optional_yield y, const std::string& package_name)
3404{
3405 // add package to list
3406 const bufferlist empty_bl;
3407 std::map<std::string, bufferlist> new_package{{package_name, empty_bl}};
3408 librados::ObjectWriteOperation op;
3409 op.omap_set(new_package);
3410 auto ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()),
3411 PACKAGE_LIST_OBJECT_NAME, &op, y);
3412
3413 if (ret < 0) {
3414 return ret;
3415 }
3416 return 0;
3417}
3418
3419int RadosLuaManager::remove_package(const DoutPrefixProvider *dpp, optional_yield y, const std::string& package_name)
3420{
3421 librados::ObjectWriteOperation op;
3422 size_t pos = package_name.find(" ");
3423 if (pos != package_name.npos) {
3424 // remove specfic version of the the package
3425 op.omap_rm_keys(std::set<std::string>({package_name}));
3426 auto ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()),
3427 PACKAGE_LIST_OBJECT_NAME, &op, y);
3428 if (ret < 0) {
3429 return ret;
3430 }
3431 return 0;
3432 }
3433 // otherwise, remove any existing versions of the package
3434 rgw::lua::packages_t packages;
3435 auto ret = list_packages(dpp, y, packages);
3436 if (ret < 0 && ret != -ENOENT) {
3437 return ret;
3438 }
3439 for(const auto& package : packages) {
3440 const std::string package_no_version = package.substr(0, package.find(" "));
3441 if (package_no_version.compare(package_name) == 0) {
3442 op.omap_rm_keys(std::set<std::string>({package}));
3443 ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()),
3444 PACKAGE_LIST_OBJECT_NAME, &op, y);
3445 if (ret < 0) {
3446 return ret;
3447 }
3448 }
3449 }
3450 return 0;
3451}
3452
3453int RadosLuaManager::list_packages(const DoutPrefixProvider *dpp, optional_yield y, rgw::lua::packages_t& packages)
3454{
3455 constexpr auto max_chunk = 1024U;
3456 std::string start_after;
3457 bool more = true;
3458 int rval;
3459 while (more) {
3460 librados::ObjectReadOperation op;
3461 rgw::lua::packages_t packages_chunk;
3462 op.omap_get_keys2(start_after, max_chunk, &packages_chunk, &more, &rval);
3463 const auto ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()),
3464 PACKAGE_LIST_OBJECT_NAME, &op, nullptr, y);
3465
3466 if (ret < 0) {
3467 return ret;
3468 }
3469
3470 packages.merge(packages_chunk);
3471 }
3472
3473 return 0;
3474}
3475
20effc67
TL
3476int RadosOIDCProvider::store_url(const DoutPrefixProvider *dpp, const std::string& url, bool exclusive, optional_yield y)
3477{
1e59de90 3478 auto sysobj = store->svc()->sysobj;
20effc67
TL
3479 std::string oid = tenant + get_url_oid_prefix() + url;
3480
3481 bufferlist bl;
3482 using ceph::encode;
3483 encode(*this, bl);
1e59de90 3484 return rgw_put_system_obj(dpp, sysobj, store->svc()->zone->get_zone_params().oidc_pool, oid, bl, exclusive, nullptr, real_time(), y);
f67539c2
TL
3485}
3486
20effc67 3487int RadosOIDCProvider::read_url(const DoutPrefixProvider *dpp, const std::string& url, const std::string& tenant)
f67539c2 3488{
1e59de90
TL
3489 auto sysobj = store->svc()->sysobj;
3490 auto& pool = store->svc()->zone->get_zone_params().oidc_pool;
20effc67
TL
3491 std::string oid = tenant + get_url_oid_prefix() + url;
3492 bufferlist bl;
3493
1e59de90 3494 int ret = rgw_get_system_obj(sysobj, pool, oid, bl, nullptr, nullptr, null_yield, dpp);
20effc67
TL
3495 if (ret < 0) {
3496 return ret;
3497 }
3498
3499 try {
3500 using ceph::decode;
3501 auto iter = bl.cbegin();
3502 decode(*this, iter);
3503 } catch (buffer::error& err) {
3504 ldpp_dout(dpp, 0) << "ERROR: failed to decode oidc provider info from pool: " << pool.name <<
3505 ": " << url << dendl;
3506 return -EIO;
3507 }
f67539c2 3508
20effc67
TL
3509 return 0;
3510}
f67539c2 3511
20effc67
TL
3512int RadosOIDCProvider::delete_obj(const DoutPrefixProvider *dpp, optional_yield y)
3513{
1e59de90 3514 auto& pool = store->svc()->zone->get_zone_params().oidc_pool;
f67539c2 3515
20effc67
TL
3516 std::string url, tenant;
3517 auto ret = get_tenant_url_from_arn(tenant, url);
f67539c2 3518 if (ret < 0) {
20effc67
TL
3519 ldpp_dout(dpp, 0) << "ERROR: failed to parse arn" << dendl;
3520 return -EINVAL;
f67539c2
TL
3521 }
3522
20effc67
TL
3523 if (this->tenant != tenant) {
3524 ldpp_dout(dpp, 0) << "ERROR: tenant in arn doesn't match that of user " << this->tenant << ", "
3525 << tenant << ": " << dendl;
3526 return -EINVAL;
f67539c2
TL
3527 }
3528
20effc67
TL
3529 // Delete url
3530 std::string oid = tenant + get_url_oid_prefix() + url;
3531 ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3532 if (ret < 0) {
3533 ldpp_dout(dpp, 0) << "ERROR: deleting oidc url from pool: " << pool.name << ": "
3534 << provider_url << ": " << cpp_strerror(-ret) << dendl;
3535 }
3536
3537 return ret;
f67539c2
TL
3538}
3539
20effc67 3540int RadosRole::store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y)
f67539c2 3541{
20effc67 3542 using ceph::encode;
39ae355f
TL
3543 std::string oid;
3544
3545 oid = info.id;
20effc67
TL
3546
3547 bufferlist bl;
39ae355f 3548 encode(this->info, bl);
20effc67 3549
39ae355f 3550 if (!this->info.tags.empty()) {
20effc67 3551 bufferlist bl_tags;
39ae355f 3552 encode(this->info.tags, bl_tags);
20effc67
TL
3553 map<string, bufferlist> attrs;
3554 attrs.emplace("tagging", bl_tags);
20effc67 3555
39ae355f
TL
3556 RGWSI_MBSObj_PutParams params(bl, &attrs, info.mtime, exclusive);
3557 std::unique_ptr<RGWSI_MetaBackend::Context> ctx(store->svc()->role->svc.meta_be->alloc_ctx());
3558 ctx->init(store->svc()->role->get_be_handler());
3559 return store->svc()->role->svc.meta_be->put(ctx.get(), oid, params, &info.objv_tracker, y, dpp);
3560 } else {
3561 RGWSI_MBSObj_PutParams params(bl, nullptr, info.mtime, exclusive);
3562 std::unique_ptr<RGWSI_MetaBackend::Context> ctx(store->svc()->role->svc.meta_be->alloc_ctx());
3563 ctx->init(store->svc()->role->get_be_handler());
3564 return store->svc()->role->svc.meta_be->put(ctx.get(), oid, params, &info.objv_tracker, y, dpp);
3565 }
20effc67
TL
3566}
3567
3568int RadosRole::store_name(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y)
3569{
1e59de90 3570 auto sysobj = store->svc()->sysobj;
20effc67 3571 RGWNameToId nameToId;
39ae355f 3572 nameToId.obj_id = info.id;
20effc67 3573
39ae355f 3574 std::string oid = info.tenant + get_names_oid_prefix() + info.name;
20effc67
TL
3575
3576 bufferlist bl;
3577 using ceph::encode;
3578 encode(nameToId, bl);
3579
1e59de90 3580 return rgw_put_system_obj(dpp, sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, exclusive, &info.objv_tracker, real_time(), y);
20effc67
TL
3581}
3582
3583int RadosRole::store_path(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y)
3584{
1e59de90 3585 auto sysobj = store->svc()->sysobj;
39ae355f 3586 std::string oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id;
20effc67
TL
3587
3588 bufferlist bl;
3589
1e59de90 3590 return rgw_put_system_obj(dpp, sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, exclusive, &info.objv_tracker, real_time(), y);
20effc67
TL
3591}
3592
3593int RadosRole::read_id(const DoutPrefixProvider *dpp, const std::string& role_name, const std::string& tenant, std::string& role_id, optional_yield y)
3594{
1e59de90 3595 auto sysobj = store->svc()->sysobj;
39ae355f 3596 std::string oid = info.tenant + get_names_oid_prefix() + role_name;
20effc67
TL
3597 bufferlist bl;
3598
1e59de90 3599 int ret = rgw_get_system_obj(sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, nullptr, nullptr, y, dpp);
20effc67
TL
3600 if (ret < 0) {
3601 return ret;
3602 }
3603
3604 RGWNameToId nameToId;
3605 try {
3606 auto iter = bl.cbegin();
3607 using ceph::decode;
3608 decode(nameToId, iter);
3609 } catch (buffer::error& err) {
3610 ldpp_dout(dpp, 0) << "ERROR: failed to decode role from Role pool: " << role_name << dendl;
3611 return -EIO;
3612 }
3613 role_id = nameToId.obj_id;
3614 return 0;
3615}
3616
3617int RadosRole::read_name(const DoutPrefixProvider *dpp, optional_yield y)
3618{
1e59de90 3619 auto sysobj = store->svc()->sysobj;
39ae355f 3620 std::string oid = info.tenant + get_names_oid_prefix() + info.name;
20effc67
TL
3621 bufferlist bl;
3622
1e59de90 3623 int ret = rgw_get_system_obj(sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, nullptr, nullptr, y, dpp);
20effc67 3624 if (ret < 0) {
39ae355f 3625 ldpp_dout(dpp, 0) << "ERROR: failed reading role name from Role pool: " << info.name <<
20effc67
TL
3626 ": " << cpp_strerror(-ret) << dendl;
3627 return ret;
3628 }
3629
3630 RGWNameToId nameToId;
3631 try {
3632 using ceph::decode;
3633 auto iter = bl.cbegin();
3634 decode(nameToId, iter);
3635 } catch (buffer::error& err) {
39ae355f 3636 ldpp_dout(dpp, 0) << "ERROR: failed to decode role name from Role pool: " << info.name << dendl;
20effc67
TL
3637 return -EIO;
3638 }
39ae355f 3639 info.id = nameToId.obj_id;
20effc67
TL
3640 return 0;
3641}
3642
3643int RadosRole::read_info(const DoutPrefixProvider *dpp, optional_yield y)
3644{
39ae355f
TL
3645 std::string oid;
3646
3647 oid = info.id;
3648 ldpp_dout(dpp, 20) << "INFO: oid in read_info is: " << oid << dendl;
3649
20effc67
TL
3650 bufferlist bl;
3651
39ae355f
TL
3652 RGWSI_MBSObj_GetParams params(&bl, &info.attrs, &info.mtime);
3653 std::unique_ptr<RGWSI_MetaBackend::Context> ctx(store->svc()->role->svc.meta_be->alloc_ctx());
3654 ctx->init(store->svc()->role->get_be_handler());
3655 int ret = store->svc()->role->svc.meta_be->get(ctx.get(), oid, params, &info.objv_tracker, y, dpp, true);
20effc67 3656 if (ret < 0) {
39ae355f 3657 ldpp_dout(dpp, 0) << "ERROR: failed reading role info from Role pool: " << info.id << ": " << cpp_strerror(-ret) << dendl;
20effc67
TL
3658 return ret;
3659 }
3660
3661 try {
3662 using ceph::decode;
3663 auto iter = bl.cbegin();
39ae355f 3664 decode(this->info, iter);
20effc67 3665 } catch (buffer::error& err) {
39ae355f 3666 ldpp_dout(dpp, 0) << "ERROR: failed to decode role info from Role pool: " << info.id << dendl;
20effc67
TL
3667 return -EIO;
3668 }
3669
39ae355f
TL
3670 auto it = info.attrs.find("tagging");
3671 if (it != info.attrs.end()) {
20effc67
TL
3672 bufferlist bl_tags = it->second;
3673 try {
3674 using ceph::decode;
3675 auto iter = bl_tags.cbegin();
39ae355f 3676 decode(info.tags, iter);
20effc67 3677 } catch (buffer::error& err) {
39ae355f 3678 ldpp_dout(dpp, 0) << "ERROR: failed to decode attrs" << info.id << dendl;
20effc67
TL
3679 return -EIO;
3680 }
3681 }
3682
3683 return 0;
f67539c2
TL
3684}
3685
39ae355f 3686int RadosRole::create(const DoutPrefixProvider *dpp, bool exclusive, const std::string& role_id, optional_yield y)
f67539c2 3687{
20effc67
TL
3688 int ret;
3689
3690 if (! validate_input(dpp)) {
3691 return -EINVAL;
3692 }
3693
39ae355f
TL
3694 if (!role_id.empty()) {
3695 info.id = role_id;
3696 }
3697
20effc67 3698 /* check to see the name is not used */
39ae355f 3699 ret = read_id(dpp, info.name, info.tenant, info.id, y);
20effc67 3700 if (exclusive && ret == 0) {
39ae355f
TL
3701 ldpp_dout(dpp, 0) << "ERROR: name " << info.name << " already in use for role id "
3702 << info.id << dendl;
20effc67
TL
3703 return -EEXIST;
3704 } else if ( ret < 0 && ret != -ENOENT) {
39ae355f 3705 ldpp_dout(dpp, 0) << "failed reading role id " << info.id << ": "
20effc67
TL
3706 << cpp_strerror(-ret) << dendl;
3707 return ret;
3708 }
3709
39ae355f
TL
3710 if (info.id.empty()) {
3711 /* create unique id */
3712 uuid_d new_uuid;
3713 char uuid_str[37];
3714 new_uuid.generate_random();
3715 new_uuid.print(uuid_str);
3716 info.id = uuid_str;
3717 }
20effc67
TL
3718
3719 //arn
39ae355f 3720 info.arn = role_arn_prefix + info.tenant + ":role" + info.path + info.name;
20effc67
TL
3721
3722 // Creation time
3723 real_clock::time_point t = real_clock::now();
3724
3725 struct timeval tv;
3726 real_clock::to_timeval(t, tv);
3727
3728 char buf[30];
3729 struct tm result;
3730 gmtime_r(&tv.tv_sec, &result);
3731 strftime(buf,30,"%Y-%m-%dT%H:%M:%S", &result);
3732 sprintf(buf + strlen(buf),".%dZ",(int)tv.tv_usec/1000);
39ae355f 3733 info.creation_date.assign(buf, strlen(buf));
20effc67 3734
1e59de90 3735 auto& pool = store->svc()->zone->get_zone_params().roles_pool;
20effc67
TL
3736 ret = store_info(dpp, exclusive, y);
3737 if (ret < 0) {
3738 ldpp_dout(dpp, 0) << "ERROR: storing role info in Role pool: "
39ae355f 3739 << info.id << ": " << cpp_strerror(-ret) << dendl;
20effc67
TL
3740 return ret;
3741 }
3742
3743 ret = store_name(dpp, exclusive, y);
3744 if (ret < 0) {
3745 ldpp_dout(dpp, 0) << "ERROR: storing role name in Role pool: "
39ae355f 3746 << info.name << ": " << cpp_strerror(-ret) << dendl;
20effc67
TL
3747
3748 //Delete the role info that was stored in the previous call
39ae355f 3749 std::string oid = get_info_oid_prefix() + info.id;
20effc67
TL
3750 int info_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3751 if (info_ret < 0) {
3752 ldpp_dout(dpp, 0) << "ERROR: cleanup of role id from Role pool: "
39ae355f 3753 << info.id << ": " << cpp_strerror(-info_ret) << dendl;
20effc67
TL
3754 }
3755 return ret;
3756 }
3757
3758 ret = store_path(dpp, exclusive, y);
3759 if (ret < 0) {
3760 ldpp_dout(dpp, 0) << "ERROR: storing role path in Role pool: "
39ae355f 3761 << info.path << ": " << cpp_strerror(-ret) << dendl;
20effc67 3762 //Delete the role info that was stored in the previous call
39ae355f 3763 std::string oid = get_info_oid_prefix() + info.id;
20effc67
TL
3764 int info_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3765 if (info_ret < 0) {
3766 ldpp_dout(dpp, 0) << "ERROR: cleanup of role id from Role pool: "
39ae355f 3767 << info.id << ": " << cpp_strerror(-info_ret) << dendl;
20effc67
TL
3768 }
3769 //Delete role name that was stored in previous call
39ae355f 3770 oid = info.tenant + get_names_oid_prefix() + info.name;
20effc67
TL
3771 int name_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3772 if (name_ret < 0) {
3773 ldpp_dout(dpp, 0) << "ERROR: cleanup of role name from Role pool: "
39ae355f 3774 << info.name << ": " << cpp_strerror(-name_ret) << dendl;
20effc67
TL
3775 }
3776 return ret;
3777 }
3778 return 0;
3779}
3780
3781int RadosRole::delete_obj(const DoutPrefixProvider *dpp, optional_yield y)
3782{
1e59de90 3783 auto& pool = store->svc()->zone->get_zone_params().roles_pool;
f67539c2 3784
20effc67
TL
3785 int ret = read_name(dpp, y);
3786 if (ret < 0) {
3787 return ret;
3788 }
3789
3790 ret = read_info(dpp, y);
3791 if (ret < 0) {
3792 return ret;
3793 }
3794
39ae355f 3795 if (! info.perm_policy_map.empty()) {
20effc67
TL
3796 return -ERR_DELETE_CONFLICT;
3797 }
3798
3799 // Delete id
39ae355f 3800 std::string oid = get_info_oid_prefix() + info.id;
20effc67
TL
3801 ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3802 if (ret < 0) {
3803 ldpp_dout(dpp, 0) << "ERROR: deleting role id from Role pool: "
39ae355f 3804 << info.id << ": " << cpp_strerror(-ret) << dendl;
20effc67
TL
3805 }
3806
3807 // Delete name
39ae355f 3808 oid = info.tenant + get_names_oid_prefix() + info.name;
20effc67
TL
3809 ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3810 if (ret < 0) {
3811 ldpp_dout(dpp, 0) << "ERROR: deleting role name from Role pool: "
39ae355f 3812 << info.name << ": " << cpp_strerror(-ret) << dendl;
20effc67
TL
3813 }
3814
3815 // Delete path
39ae355f 3816 oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id;
20effc67
TL
3817 ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
3818 if (ret < 0) {
3819 ldpp_dout(dpp, 0) << "ERROR: deleting role path from Role pool: "
39ae355f 3820 << info.path << ": " << cpp_strerror(-ret) << dendl;
20effc67
TL
3821 }
3822 return ret;
3823}
3824
20effc67
TL
3825} // namespace rgw::sal
3826
3827extern "C" {
3828
1e59de90 3829void* newRadosStore(void)
20effc67
TL
3830{
3831 rgw::sal::RadosStore* store = new rgw::sal::RadosStore();
3832 if (store) {
3833 RGWRados* rados = new RGWRados();
3834
3835 if (!rados) {
3836 delete store; store = nullptr;
3837 } else {
3838 store->setRados(rados);
3839 rados->set_store(store);
3840 }
3841 }
3842
3843 return store;
3844}
f67539c2 3845
f67539c2 3846}