]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_bucket.cc
import ceph pacific 16.2.5
[ceph.git] / ceph / src / rgw / rgw_bucket.cc
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae 3
f67539c2 4#include <cerrno>
7c673cae
FG
5#include <map>
6#include <sstream>
f67539c2
TL
7#include <string>
8#include <string_view>
7c673cae 9
7c673cae
FG
10#include <boost/format.hpp>
11
12#include "common/errno.h"
13#include "common/ceph_json.h"
f64942e4 14#include "include/scope_guard.h"
9f95a23c 15
f67539c2 16#include "rgw_datalog.h"
7c673cae 17#include "rgw_rados.h"
11fdf7f2 18#include "rgw_zone.h"
7c673cae
FG
19#include "rgw_acl.h"
20#include "rgw_acl_s3.h"
9f95a23c 21#include "rgw_tag_s3.h"
7c673cae
FG
22
23#include "include/types.h"
24#include "rgw_bucket.h"
25#include "rgw_user.h"
26#include "rgw_string.h"
224ce89b 27#include "rgw_multi.h"
9f95a23c
TL
28#include "rgw_op.h"
29#include "rgw_bucket_sync.h"
7c673cae 30
11fdf7f2
TL
31#include "services/svc_zone.h"
32#include "services/svc_sys_obj.h"
9f95a23c
TL
33#include "services/svc_bucket.h"
34#include "services/svc_bucket_sync.h"
35#include "services/svc_meta.h"
36#include "services/svc_meta_be_sobj.h"
37#include "services/svc_user.h"
38#include "services/svc_cls.h"
39#include "services/svc_bilog_rados.h"
11fdf7f2 40
7c673cae
FG
41#include "include/rados/librados.hpp"
42// until everything is moved from rgw_common
43#include "rgw_common.h"
f64942e4 44#include "rgw_reshard.h"
11fdf7f2 45#include "rgw_lc.h"
f67539c2 46#include "rgw_bucket_layout.h"
9f95a23c
TL
47
48// stolen from src/cls/version/cls_version.cc
49#define VERSION_ATTR "ceph.objclass.version"
50
7c673cae
FG
51#include "cls/user/cls_user_types.h"
52
9f95a23c 53#include "rgw_sal.h"
f67539c2 54#include "rgw_sal_rados.h"
9f95a23c 55
7c673cae
FG
56#define dout_context g_ceph_context
57#define dout_subsys ceph_subsys_rgw
58
59#define BUCKET_TAG_TIMEOUT 30
60
9f95a23c
TL
61// default number of entries to list with each bucket listing call
62// (use marker to bridge between calls)
63static constexpr size_t listing_max_entries = 1000;
7c673cae 64
7c673cae 65
9f95a23c
TL
66/*
67 * The tenant_name is always returned on purpose. May be empty, of course.
68 */
69static void parse_bucket(const string& bucket,
70 string *tenant_name,
71 string *bucket_name,
72 string *bucket_instance = nullptr /* optional */)
7c673cae 73{
9f95a23c
TL
74 /*
75 * expected format: [tenant/]bucket:bucket_instance
76 */
77 int pos = bucket.find('/');
78 if (pos >= 0) {
79 *tenant_name = bucket.substr(0, pos);
80 } else {
81 tenant_name->clear();
82 }
83 string bn = bucket.substr(pos + 1);
84 pos = bn.find (':');
85 if (pos < 0) {
86 *bucket_name = std::move(bn);
87 return;
88 }
89 *bucket_name = bn.substr(0, pos);
90 if (bucket_instance) {
91 *bucket_instance = bn.substr(pos + 1);
92 }
93
94 /*
95 * deal with the possible tenant:bucket:bucket_instance case
96 */
97 if (tenant_name->empty()) {
98 pos = bucket_instance->find(':');
99 if (pos >= 0) {
100 *tenant_name = *bucket_name;
101 *bucket_name = bucket_instance->substr(0, pos);
102 *bucket_instance = bucket_instance->substr(pos + 1);
103 }
104 }
7c673cae
FG
105}
106
107/*
108 * Note that this is not a reversal of parse_bucket(). That one deals
109 * with the syntax we need in metadata and such. This one deals with
110 * the representation in RADOS pools. We chose '/' because it's not
111 * acceptable in bucket names and thus qualified buckets cannot conflict
112 * with the legacy or S3 buckets.
113 */
114std::string rgw_make_bucket_entry_name(const std::string& tenant_name,
115 const std::string& bucket_name) {
116 std::string bucket_entry;
117
118 if (bucket_name.empty()) {
119 bucket_entry.clear();
120 } else if (tenant_name.empty()) {
121 bucket_entry = bucket_name;
122 } else {
123 bucket_entry = tenant_name + "/" + bucket_name;
124 }
125
126 return bucket_entry;
127}
128
129/*
130 * Tenants are separated from buckets in URLs by a colon in S3.
131 * This function is not to be used on Swift URLs, not even for COPY arguments.
132 */
133void rgw_parse_url_bucket(const string &bucket, const string& auth_tenant,
134 string &tenant_name, string &bucket_name) {
135
136 int pos = bucket.find(':');
137 if (pos >= 0) {
138 /*
139 * N.B.: We allow ":bucket" syntax with explicit empty tenant in order
140 * to refer to the legacy tenant, in case users in new named tenants
141 * want to access old global buckets.
142 */
143 tenant_name = bucket.substr(0, pos);
144 bucket_name = bucket.substr(pos + 1);
145 } else {
146 tenant_name = auth_tenant;
147 bucket_name = bucket;
148 }
149}
150
151/**
152 * Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
153 * Returns: 0 on success, -ERR# on failure.
154 */
b3b6e05e
TL
155int rgw_read_user_buckets(const DoutPrefixProvider *dpp,
156 rgw::sal::RGWRadosStore * store,
7c673cae 157 const rgw_user& user_id,
9f95a23c 158 rgw::sal::RGWBucketList& buckets,
7c673cae
FG
159 const string& marker,
160 const string& end_marker,
161 uint64_t max,
f67539c2
TL
162 bool need_stats,
163 optional_yield y)
7c673cae 164{
9f95a23c 165 rgw::sal::RGWRadosUser user(store, user_id);
b3b6e05e 166 return user.list_buckets(dpp, marker, end_marker, max, need_stats, buckets, y);
7c673cae
FG
167}
168
9f95a23c 169int rgw_bucket_parse_bucket_instance(const string& bucket_instance, string *bucket_name, string *bucket_id, int *shard_id)
7c673cae 170{
9f95a23c
TL
171 auto pos = bucket_instance.rfind(':');
172 if (pos == string::npos) {
7c673cae
FG
173 return -EINVAL;
174 }
175
176 string first = bucket_instance.substr(0, pos);
177 string second = bucket_instance.substr(pos + 1);
178
9f95a23c
TL
179 pos = first.find(':');
180
181 if (pos == string::npos) {
7c673cae 182 *shard_id = -1;
9f95a23c
TL
183 *bucket_name = first;
184 *bucket_id = second;
7c673cae
FG
185 return 0;
186 }
187
9f95a23c
TL
188 *bucket_name = first.substr(0, pos);
189 *bucket_id = first.substr(pos + 1);
190
7c673cae
FG
191 string err;
192 *shard_id = strict_strtol(second.c_str(), 10, &err);
193 if (!err.empty()) {
194 return -EINVAL;
195 }
196
197 return 0;
198}
199
200// parse key in format: [tenant/]name:instance[:shard_id]
201int rgw_bucket_parse_bucket_key(CephContext *cct, const string& key,
202 rgw_bucket *bucket, int *shard_id)
203{
f67539c2
TL
204 std::string_view name{key};
205 std::string_view instance;
7c673cae
FG
206
207 // split tenant/name
208 auto pos = name.find('/');
9f95a23c 209 if (pos != string::npos) {
7c673cae
FG
210 auto tenant = name.substr(0, pos);
211 bucket->tenant.assign(tenant.begin(), tenant.end());
212 name = name.substr(pos + 1);
1911f103
TL
213 } else {
214 bucket->tenant.clear();
7c673cae
FG
215 }
216
217 // split name:instance
218 pos = name.find(':');
9f95a23c 219 if (pos != string::npos) {
7c673cae
FG
220 instance = name.substr(pos + 1);
221 name = name.substr(0, pos);
222 }
223 bucket->name.assign(name.begin(), name.end());
224
225 // split instance:shard
226 pos = instance.find(':');
9f95a23c 227 if (pos == string::npos) {
7c673cae 228 bucket->bucket_id.assign(instance.begin(), instance.end());
9f95a23c
TL
229 if (shard_id) {
230 *shard_id = -1;
231 }
7c673cae
FG
232 return 0;
233 }
234
235 // parse shard id
236 auto shard = instance.substr(pos + 1);
237 string err;
238 auto id = strict_strtol(shard.data(), 10, &err);
239 if (!err.empty()) {
9f95a23c
TL
240 if (cct) {
241 ldout(cct, 0) << "ERROR: failed to parse bucket shard '"
242 << instance.data() << "': " << err << dendl;
243 }
7c673cae
FG
244 return -EINVAL;
245 }
246
9f95a23c
TL
247 if (shard_id) {
248 *shard_id = id;
249 }
7c673cae
FG
250 instance = instance.substr(0, pos);
251 bucket->bucket_id.assign(instance.begin(), instance.end());
252 return 0;
253}
254
7c673cae
FG
255static void dump_mulipart_index_results(list<rgw_obj_index_key>& objs_to_unlink,
256 Formatter *f)
257{
d2e6a577
FG
258 for (const auto& o : objs_to_unlink) {
259 f->dump_string("object", o.name);
7c673cae 260 }
7c673cae
FG
261}
262
9f95a23c 263void check_bad_user_bucket_mapping(rgw::sal::RGWRadosStore *store, const rgw_user& user_id,
f67539c2 264 bool fix,
b3b6e05e
TL
265 optional_yield y,
266 const DoutPrefixProvider *dpp)
7c673cae 267{
9f95a23c
TL
268 rgw::sal::RGWBucketList user_buckets;
269 rgw::sal::RGWRadosUser user(store, user_id);
7c673cae
FG
270 string marker;
271
272 CephContext *cct = store->ctx();
273
274 size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk;
275
276 do {
b3b6e05e 277 int ret = user.list_buckets(dpp, marker, string(), max_entries, false, user_buckets, y);
7c673cae
FG
278 if (ret < 0) {
279 ldout(store->ctx(), 0) << "failed to read user buckets: "
280 << cpp_strerror(-ret) << dendl;
281 return;
282 }
283
f67539c2
TL
284 map<string, std::unique_ptr<rgw::sal::RGWBucket>>& buckets = user_buckets.get_buckets();
285 for (auto i = buckets.begin();
7c673cae
FG
286 i != buckets.end();
287 ++i) {
288 marker = i->first;
289
f67539c2 290 auto& bucket = i->second;
7c673cae
FG
291
292 RGWBucketInfo bucket_info;
293 real_time mtime;
b3b6e05e 294 int r = store->getRados()->get_bucket_info(store->svc(), user_id.tenant, bucket->get_name(), bucket_info, &mtime, null_yield, dpp);
7c673cae
FG
295 if (r < 0) {
296 ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket << dendl;
297 continue;
298 }
299
300 rgw_bucket& actual_bucket = bucket_info.bucket;
301
9f95a23c
TL
302 if (actual_bucket.name.compare(bucket->get_name()) != 0 ||
303 actual_bucket.tenant.compare(bucket->get_tenant()) != 0 ||
304 actual_bucket.marker.compare(bucket->get_marker()) != 0 ||
305 actual_bucket.bucket_id.compare(bucket->get_bucket_id()) != 0) {
7c673cae
FG
306 cout << "bucket info mismatch: expected " << actual_bucket << " got " << bucket << std::endl;
307 if (fix) {
308 cout << "fixing" << std::endl;
9f95a23c
TL
309 r = store->ctl()->bucket->link_bucket(user_id, actual_bucket,
310 bucket_info.creation_time,
b3b6e05e 311 null_yield, dpp);
7c673cae
FG
312 if (r < 0) {
313 cerr << "failed to fix bucket: " << cpp_strerror(-r) << std::endl;
314 }
315 }
316 }
317 }
9f95a23c 318 } while (user_buckets.is_truncated());
7c673cae
FG
319}
320
9f95a23c
TL
321// note: function type conforms to RGWRados::check_filter_t
322bool rgw_bucket_object_check_filter(const string& oid)
7c673cae
FG
323{
324 rgw_obj_key key;
325 string ns;
326 return rgw_obj_key::oid_to_key_in_ns(oid, &key, ns);
327}
328
b3b6e05e 329int rgw_remove_object(const DoutPrefixProvider *dpp, rgw::sal::RGWRadosStore *store, const RGWBucketInfo& bucket_info, const rgw_bucket& bucket, rgw_obj_key& key)
7c673cae
FG
330{
331 RGWObjectCtx rctx(store);
332
333 if (key.instance.empty()) {
334 key.instance = "null";
335 }
336
337 rgw_obj obj(bucket, key);
338
b3b6e05e 339 return store->getRados()->delete_obj(dpp, rctx, bucket_info, obj, bucket_info.versioning_status());
7c673cae
FG
340}
341
7c673cae
FG
342static int aio_wait(librados::AioCompletion *handle)
343{
344 librados::AioCompletion *c = (librados::AioCompletion *)handle;
9f95a23c 345 c->wait_for_complete();
7c673cae
FG
346 int ret = c->get_return_value();
347 c->release();
348 return ret;
349}
350
351static int drain_handles(list<librados::AioCompletion *>& pending)
352{
353 int ret = 0;
354 while (!pending.empty()) {
355 librados::AioCompletion *handle = pending.front();
356 pending.pop_front();
357 int r = aio_wait(handle);
358 if (r < 0) {
359 ret = r;
360 }
361 }
362 return ret;
363}
364
9f95a23c
TL
365int rgw_remove_bucket_bypass_gc(rgw::sal::RGWRadosStore *store, rgw_bucket& bucket,
366 int concurrent_max, bool keep_index_consistent,
b3b6e05e
TL
367 optional_yield y,
368 const DoutPrefixProvider *dpp)
7c673cae
FG
369{
370 int ret;
371 map<RGWObjCategory, RGWStorageStats> stats;
372 std::vector<rgw_bucket_dir_entry> objs;
373 map<string, bool> common_prefixes;
374 RGWBucketInfo info;
375 RGWObjectCtx obj_ctx(store);
224ce89b 376 CephContext *cct = store->ctx();
7c673cae
FG
377
378 string bucket_ver, master_ver;
379
b3b6e05e 380 ret = store->getRados()->get_bucket_info(store->svc(), bucket.tenant, bucket.name, info, NULL, null_yield, dpp);
7c673cae
FG
381 if (ret < 0)
382 return ret;
383
b3b6e05e 384 ret = store->getRados()->get_bucket_stats(dpp, info, RGW_NO_SHARD, &bucket_ver, &master_ver, stats, NULL);
7c673cae
FG
385 if (ret < 0)
386 return ret;
387
224ce89b
WB
388 string prefix, delimiter;
389
b3b6e05e 390 ret = abort_bucket_multiparts(dpp, store, cct, info, prefix, delimiter);
224ce89b
WB
391 if (ret < 0) {
392 return ret;
393 }
7c673cae 394
9f95a23c 395 RGWRados::Bucket target(store->getRados(), info);
7c673cae
FG
396 RGWRados::Bucket::List list_op(&target);
397
398 list_op.params.list_versions = true;
a8e16298 399 list_op.params.allow_unordered = true;
7c673cae
FG
400
401 std::list<librados::AioCompletion*> handles;
402
7c673cae 403 int max_aio = concurrent_max;
a8e16298
TL
404 bool is_truncated = true;
405
406 while (is_truncated) {
407 objs.clear();
b3b6e05e 408 ret = list_op.list_objects(dpp, listing_max_entries, &objs, &common_prefixes,
9f95a23c 409 &is_truncated, null_yield);
a8e16298
TL
410 if (ret < 0)
411 return ret;
7c673cae 412
7c673cae
FG
413 std::vector<rgw_bucket_dir_entry>::iterator it = objs.begin();
414 for (; it != objs.end(); ++it) {
415 RGWObjState *astate = NULL;
416 rgw_obj obj(bucket, (*it).key);
417
b3b6e05e 418 ret = store->getRados()->get_obj_state(dpp, &obj_ctx, info, obj, &astate, false, y);
7c673cae 419 if (ret == -ENOENT) {
b3b6e05e 420 ldpp_dout(dpp, 1) << "WARNING: cannot find obj state for obj " << obj.get_oid() << dendl;
7c673cae
FG
421 continue;
422 }
423 if (ret < 0) {
b3b6e05e 424 ldpp_dout(dpp, -1) << "ERROR: get obj state returned with error " << ret << dendl;
7c673cae
FG
425 return ret;
426 }
427
9f95a23c
TL
428 if (astate->manifest) {
429 RGWObjManifest& manifest = *astate->manifest;
b3b6e05e 430 RGWObjManifest::obj_iterator miter = manifest.obj_begin(dpp);
7c673cae
FG
431 rgw_obj head_obj = manifest.get_obj();
432 rgw_raw_obj raw_head_obj;
9f95a23c 433 store->getRados()->obj_to_raw(info.placement_rule, head_obj, &raw_head_obj);
7c673cae
FG
434
435
b3b6e05e 436 for (; miter != manifest.obj_end(dpp) && max_aio--; ++miter) {
7c673cae
FG
437 if (!max_aio) {
438 ret = drain_handles(handles);
9f95a23c 439 if (ret < 0) {
b3b6e05e 440 ldpp_dout(dpp, -1) << "ERROR: could not drain handles as aio completion returned with " << ret << dendl;
7c673cae
FG
441 return ret;
442 }
443 max_aio = concurrent_max;
444 }
445
f67539c2 446 rgw_raw_obj last_obj = miter.get_location().get_raw_obj(store);
7c673cae
FG
447 if (last_obj == raw_head_obj) {
448 // have the head obj deleted at the end
449 continue;
450 }
451
b3b6e05e 452 ret = store->getRados()->delete_raw_obj_aio(dpp, last_obj, handles);
7c673cae 453 if (ret < 0) {
b3b6e05e 454 ldpp_dout(dpp, -1) << "ERROR: delete obj aio failed with " << ret << dendl;
7c673cae
FG
455 return ret;
456 }
457 } // for all shadow objs
458
b3b6e05e 459 ret = store->getRados()->delete_obj_aio(dpp, head_obj, info, astate, handles, keep_index_consistent, null_yield);
7c673cae 460 if (ret < 0) {
b3b6e05e 461 ldpp_dout(dpp, -1) << "ERROR: delete obj aio failed with " << ret << dendl;
7c673cae
FG
462 return ret;
463 }
464 }
465
466 if (!max_aio) {
467 ret = drain_handles(handles);
9f95a23c 468 if (ret < 0) {
b3b6e05e 469 ldpp_dout(dpp, -1) << "ERROR: could not drain handles as aio completion returned with " << ret << dendl;
7c673cae
FG
470 return ret;
471 }
472 max_aio = concurrent_max;
473 }
eafe8130 474 obj_ctx.invalidate(obj);
7c673cae 475 } // for all RGW objects
7c673cae
FG
476 }
477
478 ret = drain_handles(handles);
9f95a23c 479 if (ret < 0) {
b3b6e05e 480 ldpp_dout(dpp, -1) << "ERROR: could not drain handles as aio completion returned with " << ret << dendl;
7c673cae
FG
481 return ret;
482 }
483
b3b6e05e 484 ret = store->ctl()->bucket->sync_user_stats(dpp, info.owner, info, y);
7c673cae 485 if (ret < 0) {
b3b6e05e 486 ldpp_dout(dpp, 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
7c673cae
FG
487 }
488
489 RGWObjVersionTracker objv_tracker;
490
a8e16298
TL
491 // this function can only be run if caller wanted children to be
492 // deleted, so we can ignore the check for children as any that
493 // remain are detritus from a prior bug
b3b6e05e 494 ret = store->getRados()->delete_bucket(info, objv_tracker, y, dpp, false);
7c673cae 495 if (ret < 0) {
b3b6e05e 496 ldpp_dout(dpp, -1) << "ERROR: could not remove bucket " << bucket.name << dendl;
7c673cae
FG
497 return ret;
498 }
499
b3b6e05e 500 ret = store->ctl()->bucket->unlink_bucket(info.owner, bucket, null_yield, dpp, false);
7c673cae 501 if (ret < 0) {
b3b6e05e 502 ldpp_dout(dpp, -1) << "ERROR: unable to remove user bucket information" << dendl;
7c673cae
FG
503 }
504
505 return ret;
506}
507
7c673cae
FG
508static void set_err_msg(std::string *sink, std::string msg)
509{
510 if (sink && !msg.empty())
511 *sink = msg;
512}
513
9f95a23c 514int RGWBucket::init(rgw::sal::RGWRadosStore *storage, RGWBucketAdminOpState& op_state,
b3b6e05e 515 optional_yield y, const DoutPrefixProvider *dpp, std::string *err_msg,
9f95a23c 516 map<string, bufferlist> *pattrs)
7c673cae 517{
9f95a23c
TL
518 if (!storage) {
519 set_err_msg(err_msg, "no storage!");
7c673cae 520 return -EINVAL;
9f95a23c 521 }
7c673cae
FG
522
523 store = storage;
524
525 rgw_user user_id = op_state.get_user_id();
9f95a23c
TL
526 bucket.tenant = user_id.tenant;
527 bucket.name = op_state.get_bucket_name();
7c673cae 528
9f95a23c 529 if (bucket.name.empty() && user_id.empty())
7c673cae 530 return -EINVAL;
9f95a23c
TL
531
532 // split possible tenant/name
533 auto pos = bucket.name.find('/');
534 if (pos != string::npos) {
535 bucket.tenant = bucket.name.substr(0, pos);
536 bucket.name = bucket.name.substr(pos + 1);
537 }
538
539 if (!bucket.name.empty()) {
540 int r = store->ctl()->bucket->read_bucket_info(
b3b6e05e 541 bucket, &bucket_info, y, dpp,
9f95a23c
TL
542 RGWBucketCtl::BucketInstance::GetParams().set_attrs(pattrs),
543 &ep_objv);
7c673cae 544 if (r < 0) {
9f95a23c 545 set_err_msg(err_msg, "failed to fetch bucket info for bucket=" + bucket.name);
7c673cae
FG
546 return r;
547 }
548
549 op_state.set_bucket(bucket_info.bucket);
550 }
551
552 if (!user_id.empty()) {
b3b6e05e 553 int r = store->ctl()->user->get_info_by_uid(dpp, user_id, &user_info, y);
9f95a23c
TL
554 if (r < 0) {
555 set_err_msg(err_msg, "failed to fetch user info");
7c673cae 556 return r;
9f95a23c 557 }
7c673cae
FG
558
559 op_state.display_name = user_info.display_name;
560 }
561
562 clear_failure();
563 return 0;
564}
565
b3b6e05e 566bool rgw_find_bucket_by_id(const DoutPrefixProvider *dpp, CephContext *cct, RGWMetadataManager *mgr,
1911f103
TL
567 const string& marker, const string& bucket_id, rgw_bucket* bucket_out)
568{
569 void *handle = NULL;
570 bool truncated = false;
571 string s;
572
b3b6e05e 573 int ret = mgr->list_keys_init(dpp, "bucket.instance", marker, &handle);
1911f103
TL
574 if (ret < 0) {
575 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
576 mgr->list_keys_complete(handle);
577 return -ret;
578 }
579 do {
580 list<string> keys;
581 ret = mgr->list_keys_next(handle, 1000, keys, &truncated);
582 if (ret < 0) {
583 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
584 mgr->list_keys_complete(handle);
585 return -ret;
586 }
587 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
588 s = *iter;
589 ret = rgw_bucket_parse_bucket_key(cct, s, bucket_out, nullptr);
590 if (ret < 0) {
591 continue;
592 }
593 if (bucket_id == bucket_out->bucket_id) {
594 mgr->list_keys_complete(handle);
595 return true;
596 }
597 }
598 } while (truncated);
599 mgr->list_keys_complete(handle);
600 return false;
601}
602
b3b6e05e 603int RGWBucket::link(RGWBucketAdminOpState& op_state, optional_yield y, const DoutPrefixProvider *dpp,
9f95a23c 604 map<string, bufferlist>& attrs, std::string *err_msg)
7c673cae
FG
605{
606 if (!op_state.is_user_op()) {
607 set_err_msg(err_msg, "empty user id");
608 return -EINVAL;
609 }
610
611 string bucket_id = op_state.get_bucket_id();
7c673cae
FG
612
613 std::string display_name = op_state.get_user_display_name();
9f95a23c
TL
614 rgw_bucket& bucket = op_state.get_bucket();
615 if (!bucket_id.empty() && bucket_id != bucket.bucket_id) {
616 set_err_msg(err_msg,
617 "specified bucket id does not match " + bucket.bucket_id);
618 return -EINVAL;
619 }
620 rgw_bucket old_bucket = bucket;
621 rgw_user user_id = op_state.get_user_id();
622 bucket.tenant = user_id.tenant;
623 if (!op_state.new_bucket_name.empty()) {
624 auto pos = op_state.new_bucket_name.find('/');
625 if (pos != string::npos) {
626 bucket.tenant = op_state.new_bucket_name.substr(0, pos);
627 bucket.name = op_state.new_bucket_name.substr(pos + 1);
628 } else {
629 bucket.name = op_state.new_bucket_name;
630 }
631 }
7c673cae 632
7c673cae 633 RGWObjVersionTracker objv_tracker;
9f95a23c 634 RGWObjVersionTracker old_version = bucket_info.objv_tracker;
7c673cae 635
9f95a23c
TL
636 map<string, bufferlist>::iterator aiter = attrs.find(RGW_ATTR_ACL);
637 if (aiter == attrs.end()) {
638 // should never happen; only pre-argonaut buckets lacked this.
b3b6e05e 639 ldpp_dout(dpp, 0) << "WARNING: can't bucket link because no acl on bucket=" << old_bucket.name << dendl;
9f95a23c
TL
640 set_err_msg(err_msg,
641 "While crossing the Anavros you have displeased the goddess Hera."
642 " You must sacrifice your ancient bucket " + bucket.bucket_id);
643 return -EINVAL;
644 }
645 bufferlist& aclbl = aiter->second;
646 RGWAccessControlPolicy policy;
647 ACLOwner owner;
648 try {
649 auto iter = aclbl.cbegin();
650 decode(policy, iter);
651 owner = policy.get_owner();
652 } catch (buffer::error& err) {
653 set_err_msg(err_msg, "couldn't decode policy");
654 return -EIO;
655 }
7c673cae 656
9f95a23c 657 auto bucket_ctl = store->ctl()->bucket;
b3b6e05e 658 int r = bucket_ctl->unlink_bucket(owner.get_id(), old_bucket, y, dpp, false);
7c673cae 659 if (r < 0) {
9f95a23c 660 set_err_msg(err_msg, "could not unlink policy from user " + owner.get_id().to_str());
7c673cae
FG
661 return r;
662 }
663
9f95a23c
TL
664 // now update the user for the bucket...
665 if (display_name.empty()) {
b3b6e05e 666 ldpp_dout(dpp, 0) << "WARNING: user " << user_info.user_id << " has no display name set" << dendl;
9f95a23c 667 }
7c673cae 668
9f95a23c
TL
669 RGWAccessControlPolicy policy_instance;
670 policy_instance.create_default(user_info.user_id, display_name);
671 owner = policy_instance.get_owner();
7c673cae 672
9f95a23c
TL
673 aclbl.clear();
674 policy_instance.encode(aclbl);
7c673cae 675
9f95a23c 676 auto instance_params = RGWBucketCtl::BucketInstance::PutParams().set_attrs(&attrs);
7c673cae 677
9f95a23c
TL
678 bucket_info.owner = user_info.user_id;
679 if (bucket != old_bucket) {
680 bucket_info.bucket = bucket;
681 bucket_info.objv_tracker.version_for_read()->ver = 0;
682 instance_params.set_exclusive(true);
683 }
7c673cae 684
b3b6e05e 685 r = bucket_ctl->store_bucket_instance_info(bucket, bucket_info, y, dpp, instance_params);
9f95a23c
TL
686 if (r < 0) {
687 set_err_msg(err_msg, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r));
688 return r;
689 }
7c673cae 690
9f95a23c
TL
691 RGWBucketEntryPoint ep;
692 ep.bucket = bucket_info.bucket;
693 ep.owner = user_info.user_id;
694 ep.creation_time = bucket_info.creation_time;
695 ep.linked = true;
696 map<string, bufferlist> ep_attrs;
697 rgw_ep_info ep_data{ep, ep_attrs};
698
699 /* link to user */
700 r = store->ctl()->bucket->link_bucket(user_info.user_id,
701 bucket_info.bucket,
702 ep.creation_time,
b3b6e05e 703 y, dpp, true, &ep_data);
9f95a23c
TL
704 if (r < 0) {
705 set_err_msg(err_msg, "failed to relink bucket");
706 return r;
707 }
7c673cae 708
9f95a23c
TL
709 if (bucket != old_bucket) {
710 // like RGWRados::delete_bucket -- excepting no bucket_index work.
b3b6e05e 711 r = bucket_ctl->remove_bucket_entrypoint_info(old_bucket, y, dpp,
9f95a23c
TL
712 RGWBucketCtl::Bucket::RemoveParams()
713 .set_objv_tracker(&ep_data.ep_objv));
224ce89b 714 if (r < 0) {
9f95a23c 715 set_err_msg(err_msg, "failed to unlink old bucket endpoint " + old_bucket.tenant + "/" + old_bucket.name);
224ce89b
WB
716 return r;
717 }
7c673cae 718
b3b6e05e 719 r = bucket_ctl->remove_bucket_instance_info(old_bucket, bucket_info, y, dpp,
9f95a23c
TL
720 RGWBucketCtl::BucketInstance::RemoveParams()
721 .set_objv_tracker(&old_version));
224ce89b 722 if (r < 0) {
9f95a23c 723 set_err_msg(err_msg, "failed to unlink old bucket info");
7c673cae 724 return r;
224ce89b 725 }
7c673cae
FG
726 }
727
728 return 0;
729}
730
9f95a23c 731int RGWBucket::chown(RGWBucketAdminOpState& op_state, const string& marker,
b3b6e05e 732 optional_yield y, const DoutPrefixProvider *dpp, std::string *err_msg)
9f95a23c
TL
733{
734 int ret = store->ctl()->bucket->chown(store, bucket_info, user_info.user_id,
b3b6e05e 735 user_info.display_name, marker, y, dpp);
9f95a23c
TL
736 if (ret < 0) {
737 set_err_msg(err_msg, "Failed to change object ownership: " + cpp_strerror(-ret));
738 }
739
740 return ret;
741}
742
b3b6e05e 743int RGWBucket::unlink(RGWBucketAdminOpState& op_state, optional_yield y, const DoutPrefixProvider *dpp, std::string *err_msg)
7c673cae
FG
744{
745 rgw_bucket bucket = op_state.get_bucket();
746
747 if (!op_state.is_user_op()) {
748 set_err_msg(err_msg, "could not fetch user or user bucket info");
749 return -EINVAL;
750 }
751
b3b6e05e 752 int r = store->ctl()->bucket->unlink_bucket(user_info.user_id, bucket, y, dpp);
7c673cae
FG
753 if (r < 0) {
754 set_err_msg(err_msg, "error unlinking bucket" + cpp_strerror(-r));
755 }
756
757 return r;
758}
759
b3b6e05e 760int RGWBucket::set_quota(RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, std::string *err_msg)
94b18763
FG
761{
762 rgw_bucket bucket = op_state.get_bucket();
763 RGWBucketInfo bucket_info;
764 map<string, bufferlist> attrs;
b3b6e05e 765 int r = store->getRados()->get_bucket_info(store->svc(), bucket.tenant, bucket.name, bucket_info, NULL, null_yield, dpp, &attrs);
94b18763
FG
766 if (r < 0) {
767 set_err_msg(err_msg, "could not get bucket info for bucket=" + bucket.name + ": " + cpp_strerror(-r));
768 return r;
769 }
770
771 bucket_info.quota = op_state.quota;
b3b6e05e 772 r = store->getRados()->put_bucket_instance_info(bucket_info, false, real_time(), &attrs, dpp);
94b18763
FG
773 if (r < 0) {
774 set_err_msg(err_msg, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r));
775 return r;
776 }
777 return r;
778}
779
b3b6e05e 780int RGWBucket::remove_object(const DoutPrefixProvider *dpp, RGWBucketAdminOpState& op_state, std::string *err_msg)
7c673cae
FG
781{
782 rgw_bucket bucket = op_state.get_bucket();
783 std::string object_name = op_state.get_object_name();
784
785 rgw_obj_key key(object_name);
786
b3b6e05e 787 int ret = rgw_remove_object(dpp, store, bucket_info, bucket, key);
7c673cae
FG
788 if (ret < 0) {
789 set_err_msg(err_msg, "unable to remove object" + cpp_strerror(-ret));
790 return ret;
791 }
792
793 return 0;
794}
795
9f95a23c 796static void dump_bucket_index(const RGWRados::ent_map_t& result, Formatter *f)
7c673cae 797{
9f95a23c 798 for (auto iter = result.begin(); iter != result.end(); ++iter) {
7c673cae 799 f->dump_string("object", iter->first);
9f95a23c 800 }
7c673cae
FG
801}
802
803static void dump_bucket_usage(map<RGWObjCategory, RGWStorageStats>& stats, Formatter *formatter)
804{
805 map<RGWObjCategory, RGWStorageStats>::iterator iter;
806
807 formatter->open_object_section("usage");
808 for (iter = stats.begin(); iter != stats.end(); ++iter) {
809 RGWStorageStats& s = iter->second;
810 const char *cat_name = rgw_obj_category_name(iter->first);
811 formatter->open_object_section(cat_name);
812 s.dump(formatter);
813 formatter->close_section();
814 }
815 formatter->close_section();
816}
817
818static void dump_index_check(map<RGWObjCategory, RGWStorageStats> existing_stats,
819 map<RGWObjCategory, RGWStorageStats> calculated_stats,
820 Formatter *formatter)
821{
822 formatter->open_object_section("check_result");
823 formatter->open_object_section("existing_header");
824 dump_bucket_usage(existing_stats, formatter);
825 formatter->close_section();
826 formatter->open_object_section("calculated_header");
827 dump_bucket_usage(calculated_stats, formatter);
828 formatter->close_section();
829 formatter->close_section();
830}
831
832int RGWBucket::check_bad_index_multipart(RGWBucketAdminOpState& op_state,
b3b6e05e
TL
833 RGWFormatterFlusher& flusher,
834 const DoutPrefixProvider *dpp, std::string *err_msg)
7c673cae
FG
835{
836 bool fix_index = op_state.will_fix_index();
837 rgw_bucket bucket = op_state.get_bucket();
838
7c673cae
FG
839 map<string, bool> common_prefixes;
840
841 bool is_truncated;
842 map<string, bool> meta_objs;
843 map<rgw_obj_index_key, string> all_objs;
844
845 RGWBucketInfo bucket_info;
9f95a23c 846 auto obj_ctx = store->svc()->sysobj->init_obj_ctx();
b3b6e05e 847 int r = store->getRados()->get_bucket_instance_info(obj_ctx, bucket, bucket_info, nullptr, nullptr, null_yield, dpp);
7c673cae 848 if (r < 0) {
b3b6e05e 849 ldpp_dout(dpp, 0) << "ERROR: " << __func__ << "(): get_bucket_instance_info(bucket=" << bucket << ") returned r=" << r << dendl;
7c673cae
FG
850 return r;
851 }
852
9f95a23c 853 RGWRados::Bucket target(store->getRados(), bucket_info);
7c673cae
FG
854 RGWRados::Bucket::List list_op(&target);
855
856 list_op.params.list_versions = true;
224ce89b 857 list_op.params.ns = RGW_OBJ_NS_MULTIPART;
7c673cae
FG
858
859 do {
860 vector<rgw_bucket_dir_entry> result;
b3b6e05e 861 int r = list_op.list_objects(dpp, listing_max_entries, &result,
9f95a23c 862 &common_prefixes, &is_truncated, null_yield);
7c673cae
FG
863 if (r < 0) {
864 set_err_msg(err_msg, "failed to list objects in bucket=" + bucket.name +
865 " err=" + cpp_strerror(-r));
866
867 return r;
868 }
869
870 vector<rgw_bucket_dir_entry>::iterator iter;
871 for (iter = result.begin(); iter != result.end(); ++iter) {
31f18b77
FG
872 rgw_obj_index_key key = iter->key;
873 rgw_obj obj(bucket, key);
874 string oid = obj.get_oid();
7c673cae
FG
875
876 int pos = oid.find_last_of('.');
877 if (pos < 0) {
878 /* obj has no suffix */
879 all_objs[key] = oid;
880 } else {
881 /* obj has suffix */
882 string name = oid.substr(0, pos);
883 string suffix = oid.substr(pos + 1);
884
885 if (suffix.compare("meta") == 0) {
886 meta_objs[name] = true;
887 } else {
888 all_objs[key] = name;
889 }
890 }
891 }
7c673cae
FG
892 } while (is_truncated);
893
d2e6a577
FG
894 list<rgw_obj_index_key> objs_to_unlink;
895 Formatter *f = flusher.get_formatter();
896
897 f->open_array_section("invalid_multipart_entries");
898
7c673cae
FG
899 for (auto aiter = all_objs.begin(); aiter != all_objs.end(); ++aiter) {
900 string& name = aiter->second;
901
7c673cae
FG
902 if (meta_objs.find(name) == meta_objs.end()) {
903 objs_to_unlink.push_back(aiter->first);
904 }
7c673cae 905
9f95a23c 906 if (objs_to_unlink.size() > listing_max_entries) {
d2e6a577 907 if (fix_index) {
b3b6e05e 908 int r = store->getRados()->remove_objs_from_index(dpp, bucket_info, objs_to_unlink);
d2e6a577
FG
909 if (r < 0) {
910 set_err_msg(err_msg, "ERROR: remove_obj_from_index() returned error: " +
911 cpp_strerror(-r));
912 return r;
913 }
914 }
915
916 dump_mulipart_index_results(objs_to_unlink, flusher.get_formatter());
917 flusher.flush();
918 objs_to_unlink.clear();
919 }
920 }
7c673cae
FG
921
922 if (fix_index) {
b3b6e05e 923 int r = store->getRados()->remove_objs_from_index(dpp, bucket_info, objs_to_unlink);
7c673cae
FG
924 if (r < 0) {
925 set_err_msg(err_msg, "ERROR: remove_obj_from_index() returned error: " +
926 cpp_strerror(-r));
927
928 return r;
929 }
930 }
931
d2e6a577
FG
932 dump_mulipart_index_results(objs_to_unlink, f);
933 f->close_section();
934 flusher.flush();
935
7c673cae
FG
936 return 0;
937}
938
b3b6e05e
TL
939int RGWBucket::check_object_index(const DoutPrefixProvider *dpp,
940 RGWBucketAdminOpState& op_state,
7c673cae 941 RGWFormatterFlusher& flusher,
9f95a23c 942 optional_yield y,
7c673cae
FG
943 std::string *err_msg)
944{
945
946 bool fix_index = op_state.will_fix_index();
947
7c673cae
FG
948 if (!fix_index) {
949 set_err_msg(err_msg, "check-objects flag requires fix index enabled");
950 return -EINVAL;
951 }
952
b3b6e05e 953 store->getRados()->cls_obj_set_bucket_tag_timeout(dpp, bucket_info, BUCKET_TAG_TIMEOUT);
7c673cae
FG
954
955 string prefix;
9f95a23c 956 string empty_delimiter;
7c673cae
FG
957 rgw_obj_index_key marker;
958 bool is_truncated = true;
9f95a23c 959 bool cls_filtered = true;
7c673cae
FG
960
961 Formatter *formatter = flusher.get_formatter();
962 formatter->open_object_section("objects");
9f95a23c 963 uint16_t expansion_factor = 1;
7c673cae 964 while (is_truncated) {
9f95a23c
TL
965 RGWRados::ent_map_t result;
966 result.reserve(listing_max_entries);
967
968 int r = store->getRados()->cls_bucket_list_ordered(
b3b6e05e 969 dpp, bucket_info, RGW_NO_SHARD, marker, prefix, empty_delimiter,
9f95a23c
TL
970 listing_max_entries, true, expansion_factor,
971 result, &is_truncated, &cls_filtered, &marker,
972 y, rgw_bucket_object_check_filter);
7c673cae
FG
973 if (r == -ENOENT) {
974 break;
975 } else if (r < 0 && r != -ENOENT) {
976 set_err_msg(err_msg, "ERROR: failed operation r=" + cpp_strerror(-r));
977 }
978
9f95a23c
TL
979 if (result.size() < listing_max_entries / 8) {
980 ++expansion_factor;
981 } else if (result.size() > listing_max_entries * 7 / 8 &&
982 expansion_factor > 1) {
983 --expansion_factor;
984 }
985
7c673cae
FG
986 dump_bucket_index(result, formatter);
987 flusher.flush();
7c673cae
FG
988 }
989
990 formatter->close_section();
991
b3b6e05e 992 store->getRados()->cls_obj_set_bucket_tag_timeout(dpp, bucket_info, 0);
7c673cae
FG
993
994 return 0;
995}
996
997
b3b6e05e
TL
998int RGWBucket::check_index(const DoutPrefixProvider *dpp,
999 RGWBucketAdminOpState& op_state,
7c673cae
FG
1000 map<RGWObjCategory, RGWStorageStats>& existing_stats,
1001 map<RGWObjCategory, RGWStorageStats>& calculated_stats,
1002 std::string *err_msg)
1003{
7c673cae
FG
1004 bool fix_index = op_state.will_fix_index();
1005
b3b6e05e 1006 int r = store->getRados()->bucket_check_index(dpp, bucket_info, &existing_stats, &calculated_stats);
7c673cae
FG
1007 if (r < 0) {
1008 set_err_msg(err_msg, "failed to check index error=" + cpp_strerror(-r));
1009 return r;
1010 }
1011
1012 if (fix_index) {
b3b6e05e 1013 r = store->getRados()->bucket_rebuild_index(dpp, bucket_info);
7c673cae
FG
1014 if (r < 0) {
1015 set_err_msg(err_msg, "failed to rebuild index err=" + cpp_strerror(-r));
1016 return r;
1017 }
1018 }
1019
1020 return 0;
1021}
1022
b3b6e05e 1023int RGWBucket::sync(RGWBucketAdminOpState& op_state, map<string, bufferlist> *attrs, const DoutPrefixProvider *dpp, std::string *err_msg)
7c673cae 1024{
9f95a23c
TL
1025 if (!store->svc()->zone->is_meta_master()) {
1026 set_err_msg(err_msg, "ERROR: failed to update bucket sync: only allowed on meta master zone");
1027 return EINVAL;
1028 }
1029 bool sync = op_state.will_sync_bucket();
1030 if (sync) {
1031 bucket_info.flags &= ~BUCKET_DATASYNC_DISABLED;
1032 } else {
1033 bucket_info.flags |= BUCKET_DATASYNC_DISABLED;
7c673cae 1034 }
81eedcae 1035
b3b6e05e 1036 int r = store->getRados()->put_bucket_instance_info(bucket_info, false, real_time(), attrs, dpp);
9f95a23c
TL
1037 if (r < 0) {
1038 set_err_msg(err_msg, "ERROR: failed writing bucket instance info:" + cpp_strerror(-r));
1039 return r;
1040 }
7c673cae 1041
f67539c2
TL
1042 int shards_num = bucket_info.layout.current_index.layout.normal.num_shards? bucket_info.layout.current_index.layout.normal.num_shards : 1;
1043 int shard_id = bucket_info.layout.current_index.layout.normal.num_shards? 0 : -1;
7c673cae 1044
9f95a23c 1045 if (!sync) {
b3b6e05e 1046 r = store->svc()->bilog_rados->log_stop(dpp, bucket_info, -1);
9f95a23c
TL
1047 if (r < 0) {
1048 set_err_msg(err_msg, "ERROR: failed writing stop bilog:" + cpp_strerror(-r));
1049 return r;
1050 }
1051 } else {
b3b6e05e 1052 r = store->svc()->bilog_rados->log_start(dpp, bucket_info, -1);
9f95a23c
TL
1053 if (r < 0) {
1054 set_err_msg(err_msg, "ERROR: failed writing resync bilog:" + cpp_strerror(-r));
1055 return r;
1056 }
1057 }
1058
1059 for (int i = 0; i < shards_num; ++i, ++shard_id) {
b3b6e05e 1060 r = store->svc()->datalog_rados->add_entry(dpp, bucket_info, shard_id);
9f95a23c
TL
1061 if (r < 0) {
1062 set_err_msg(err_msg, "ERROR: failed writing data log:" + cpp_strerror(-r));
1063 return r;
1064 }
1065 }
1066
1067 return 0;
1068}
1069
1070
1071int RGWBucket::policy_bl_to_stream(bufferlist& bl, ostream& o)
1072{
1073 RGWAccessControlPolicy_S3 policy(g_ceph_context);
1074 int ret = decode_bl(bl, policy);
1075 if (ret < 0) {
1076 ldout(store->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
1077 }
1078 policy.to_xml(o);
1079 return 0;
1080}
1081
b3b6e05e
TL
1082int rgw_object_get_attr(const DoutPrefixProvider *dpp,
1083 rgw::sal::RGWRadosStore* store, const RGWBucketInfo& bucket_info,
9f95a23c
TL
1084 const rgw_obj& obj, const char* attr_name,
1085 bufferlist& out_bl, optional_yield y)
1086{
1087 RGWObjectCtx obj_ctx(store);
1088 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, obj);
1089 RGWRados::Object::Read rop(&op_target);
1090
b3b6e05e 1091 return rop.get_attr(dpp, attr_name, out_bl, y);
9f95a23c
TL
1092}
1093
b3b6e05e 1094int RGWBucket::get_policy(RGWBucketAdminOpState& op_state, RGWAccessControlPolicy& policy, optional_yield y, const DoutPrefixProvider *dpp)
9f95a23c
TL
1095{
1096 std::string object_name = op_state.get_object_name();
1097 rgw_bucket bucket = op_state.get_bucket();
1098
1099 RGWBucketInfo bucket_info;
1100 map<string, bufferlist> attrs;
b3b6e05e 1101 int ret = store->getRados()->get_bucket_info(store->svc(), bucket.tenant, bucket.name, bucket_info, NULL, null_yield, dpp, &attrs);
9f95a23c 1102 if (ret < 0) {
7c673cae
FG
1103 return ret;
1104 }
1105
1106 if (!object_name.empty()) {
1107 bufferlist bl;
1108 rgw_obj obj(bucket, object_name);
1109
b3b6e05e 1110 ret = rgw_object_get_attr(dpp, store, bucket_info, obj, RGW_ATTR_ACL, bl, y);
81eedcae 1111 if (ret < 0){
7c673cae 1112 return ret;
81eedcae 1113 }
7c673cae 1114
81eedcae
TL
1115 ret = decode_bl(bl, policy);
1116 if (ret < 0) {
1117 ldout(store->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
1118 }
1119 return ret;
7c673cae
FG
1120 }
1121
1122 map<string, bufferlist>::iterator aiter = attrs.find(RGW_ATTR_ACL);
1123 if (aiter == attrs.end()) {
1124 return -ENOENT;
1125 }
1126
81eedcae
TL
1127 ret = decode_bl(aiter->second, policy);
1128 if (ret < 0) {
1129 ldout(store->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
1130 }
1131
1132 return ret;
7c673cae
FG
1133}
1134
1135
9f95a23c 1136int RGWBucketAdminOp::get_policy(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
b3b6e05e 1137 RGWAccessControlPolicy& policy, const DoutPrefixProvider *dpp)
7c673cae
FG
1138{
1139 RGWBucket bucket;
1140
b3b6e05e 1141 int ret = bucket.init(store, op_state, null_yield, dpp);
7c673cae
FG
1142 if (ret < 0)
1143 return ret;
1144
b3b6e05e 1145 ret = bucket.get_policy(op_state, policy, null_yield, dpp);
7c673cae
FG
1146 if (ret < 0)
1147 return ret;
1148
1149 return 0;
1150}
1151
1152/* Wrappers to facilitate RESTful interface */
1153
1154
9f95a23c 1155int RGWBucketAdminOp::get_policy(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
b3b6e05e 1156 RGWFormatterFlusher& flusher, const DoutPrefixProvider *dpp)
7c673cae
FG
1157{
1158 RGWAccessControlPolicy policy(store->ctx());
1159
b3b6e05e 1160 int ret = get_policy(store, op_state, policy, dpp);
7c673cae
FG
1161 if (ret < 0)
1162 return ret;
1163
1164 Formatter *formatter = flusher.get_formatter();
1165
1166 flusher.start(0);
1167
1168 formatter->open_object_section("policy");
1169 policy.dump(formatter);
1170 formatter->close_section();
1171
1172 flusher.flush();
1173
1174 return 0;
1175}
1176
9f95a23c 1177int RGWBucketAdminOp::dump_s3_policy(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
b3b6e05e 1178 ostream& os, const DoutPrefixProvider *dpp)
7c673cae
FG
1179{
1180 RGWAccessControlPolicy_S3 policy(store->ctx());
1181
b3b6e05e 1182 int ret = get_policy(store, op_state, policy, dpp);
7c673cae
FG
1183 if (ret < 0)
1184 return ret;
1185
1186 policy.to_xml(os);
1187
1188 return 0;
1189}
1190
b3b6e05e 1191int RGWBucketAdminOp::unlink(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp)
7c673cae
FG
1192{
1193 RGWBucket bucket;
1194
b3b6e05e 1195 int ret = bucket.init(store, op_state, null_yield, dpp);
7c673cae
FG
1196 if (ret < 0)
1197 return ret;
1198
b3b6e05e 1199 return bucket.unlink(op_state, null_yield, dpp);
7c673cae
FG
1200}
1201
b3b6e05e 1202int RGWBucketAdminOp::link(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, string *err)
7c673cae
FG
1203{
1204 RGWBucket bucket;
9f95a23c 1205 map<string, bufferlist> attrs;
7c673cae 1206
b3b6e05e 1207 int ret = bucket.init(store, op_state, null_yield, dpp, err, &attrs);
7c673cae
FG
1208 if (ret < 0)
1209 return ret;
1210
b3b6e05e 1211 return bucket.link(op_state, null_yield, dpp, attrs, err);
7c673cae
FG
1212
1213}
1214
b3b6e05e 1215int RGWBucketAdminOp::chown(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state, const string& marker, const DoutPrefixProvider *dpp, string *err)
9f95a23c
TL
1216{
1217 RGWBucket bucket;
1218 map<string, bufferlist> attrs;
1219
b3b6e05e 1220 int ret = bucket.init(store, op_state, null_yield, dpp, err, &attrs);
9f95a23c
TL
1221 if (ret < 0)
1222 return ret;
1223
b3b6e05e 1224 ret = bucket.link(op_state, null_yield, dpp, attrs, err);
9f95a23c
TL
1225 if (ret < 0)
1226 return ret;
1227
b3b6e05e 1228 return bucket.chown(op_state, marker, null_yield, dpp, err);
9f95a23c
TL
1229
1230}
1231
1232int RGWBucketAdminOp::check_index(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
b3b6e05e 1233 RGWFormatterFlusher& flusher, optional_yield y, const DoutPrefixProvider *dpp)
7c673cae
FG
1234{
1235 int ret;
7c673cae
FG
1236 map<RGWObjCategory, RGWStorageStats> existing_stats;
1237 map<RGWObjCategory, RGWStorageStats> calculated_stats;
d2e6a577 1238
7c673cae
FG
1239
1240 RGWBucket bucket;
1241
b3b6e05e 1242 ret = bucket.init(store, op_state, null_yield, dpp);
7c673cae
FG
1243 if (ret < 0)
1244 return ret;
1245
1246 Formatter *formatter = flusher.get_formatter();
1247 flusher.start(0);
1248
b3b6e05e 1249 ret = bucket.check_bad_index_multipart(op_state, flusher, dpp);
7c673cae
FG
1250 if (ret < 0)
1251 return ret;
1252
b3b6e05e 1253 ret = bucket.check_object_index(dpp, op_state, flusher, y);
7c673cae
FG
1254 if (ret < 0)
1255 return ret;
1256
b3b6e05e 1257 ret = bucket.check_index(dpp, op_state, existing_stats, calculated_stats);
7c673cae
FG
1258 if (ret < 0)
1259 return ret;
1260
1261 dump_index_check(existing_stats, calculated_stats, formatter);
1262 flusher.flush();
1263
1264 return 0;
1265}
1266
9f95a23c 1267int RGWBucketAdminOp::remove_bucket(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
b3b6e05e
TL
1268 optional_yield y, const DoutPrefixProvider *dpp,
1269 bool bypass_gc, bool keep_index_consistent)
7c673cae 1270{
f67539c2
TL
1271 std::unique_ptr<rgw::sal::RGWBucket> bucket;
1272 std::unique_ptr<rgw::sal::RGWUser> user = store->get_user(op_state.get_user_id());
7c673cae 1273
b3b6e05e 1274 int ret = store->get_bucket(dpp, user.get(), user->get_tenant(), op_state.get_bucket_name(),
f67539c2 1275 &bucket, y);
7c673cae
FG
1276 if (ret < 0)
1277 return ret;
1278
f67539c2 1279 if (bypass_gc)
b3b6e05e 1280 ret = rgw_remove_bucket_bypass_gc(store, bucket->get_key(), op_state.get_max_aio(), keep_index_consistent, y, dpp);
f67539c2 1281 else
b3b6e05e 1282 ret = bucket->remove_bucket(dpp, op_state.will_delete_children(), string(), string(),
f67539c2
TL
1283 false, nullptr, y);
1284
c07f9fc5 1285 return ret;
7c673cae
FG
1286}
1287
b3b6e05e 1288int RGWBucketAdminOp::remove_object(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp)
7c673cae
FG
1289{
1290 RGWBucket bucket;
1291
b3b6e05e 1292 int ret = bucket.init(store, op_state, null_yield, dpp);
7c673cae
FG
1293 if (ret < 0)
1294 return ret;
1295
b3b6e05e 1296 return bucket.remove_object(dpp, op_state);
7c673cae
FG
1297}
1298
b3b6e05e 1299int RGWBucketAdminOp::sync_bucket(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, string *err_msg)
9f95a23c
TL
1300{
1301 RGWBucket bucket;
1302 map<string, bufferlist> attrs;
b3b6e05e 1303 int ret = bucket.init(store, op_state, null_yield, dpp, err_msg, &attrs);
9f95a23c
TL
1304 if (ret < 0)
1305 {
1306 return ret;
1307 }
b3b6e05e 1308 return bucket.sync(op_state, &attrs, dpp, err_msg);
9f95a23c
TL
1309}
1310
f6b5b4d7
TL
1311static int bucket_stats(rgw::sal::RGWRadosStore *store,
1312 const std::string& tenant_name,
1313 const std::string& bucket_name,
b3b6e05e
TL
1314 Formatter *formatter,
1315 const DoutPrefixProvider *dpp)
7c673cae
FG
1316{
1317 RGWBucketInfo bucket_info;
1318 map<RGWObjCategory, RGWStorageStats> stats;
9f95a23c 1319 map<string, bufferlist> attrs;
7c673cae
FG
1320
1321 real_time mtime;
f6b5b4d7
TL
1322 int r = store->getRados()->get_bucket_info(store->svc(),
1323 tenant_name, bucket_name, bucket_info,
b3b6e05e 1324 &mtime, null_yield, dpp, &attrs);
f6b5b4d7 1325 if (r < 0) {
7c673cae 1326 return r;
f6b5b4d7 1327 }
7c673cae
FG
1328
1329 rgw_bucket& bucket = bucket_info.bucket;
1330
1331 string bucket_ver, master_ver;
1332 string max_marker;
b3b6e05e 1333 int ret = store->getRados()->get_bucket_stats(dpp, bucket_info, RGW_NO_SHARD,
f6b5b4d7
TL
1334 &bucket_ver, &master_ver, stats,
1335 &max_marker);
7c673cae 1336 if (ret < 0) {
f91f0fd5 1337 cerr << "error getting bucket stats bucket=" << bucket.name << " ret=" << ret << std::endl;
7c673cae
FG
1338 return ret;
1339 }
1340
1341 utime_t ut(mtime);
9f95a23c 1342 utime_t ctime_ut(bucket_info.creation_time);
7c673cae
FG
1343
1344 formatter->open_object_section("stats");
1345 formatter->dump_string("bucket", bucket.name);
f67539c2
TL
1346 formatter->dump_int("num_shards",
1347 bucket_info.layout.current_index.layout.normal.num_shards);
11fdf7f2 1348 formatter->dump_string("tenant", bucket.tenant);
31f18b77 1349 formatter->dump_string("zonegroup", bucket_info.zonegroup);
11fdf7f2 1350 formatter->dump_string("placement_rule", bucket_info.placement_rule.to_str());
31f18b77 1351 ::encode_json("explicit_placement", bucket.explicit_placement, formatter);
7c673cae
FG
1352 formatter->dump_string("id", bucket.bucket_id);
1353 formatter->dump_string("marker", bucket.marker);
f67539c2 1354 formatter->dump_stream("index_type") << bucket_info.layout.current_index.layout.type;
7c673cae
FG
1355 ::encode_json("owner", bucket_info.owner, formatter);
1356 formatter->dump_string("ver", bucket_ver);
1357 formatter->dump_string("master_ver", master_ver);
81eedcae 1358 ut.gmtime(formatter->dump_stream("mtime"));
9f95a23c 1359 ctime_ut.gmtime(formatter->dump_stream("creation_time"));
7c673cae
FG
1360 formatter->dump_string("max_marker", max_marker);
1361 dump_bucket_usage(stats, formatter);
1362 encode_json("bucket_quota", bucket_info.quota, formatter);
9f95a23c
TL
1363
1364 // bucket tags
1365 auto iter = attrs.find(RGW_ATTR_TAGS);
1366 if (iter != attrs.end()) {
1367 RGWObjTagSet_S3 tagset;
1368 bufferlist::const_iterator piter{&iter->second};
1369 try {
1370 tagset.decode(piter);
1371 tagset.dump(formatter);
1372 } catch (buffer::error& err) {
1373 cerr << "ERROR: caught buffer:error, couldn't decode TagSet" << std::endl;
1374 }
1375 }
1376
1377 // TODO: bucket CORS
1378 // TODO: bucket LC
7c673cae
FG
1379 formatter->close_section();
1380
1381 return 0;
1382}
1383
9f95a23c 1384int RGWBucketAdminOp::limit_check(rgw::sal::RGWRadosStore *store,
7c673cae
FG
1385 RGWBucketAdminOpState& op_state,
1386 const std::list<std::string>& user_ids,
f67539c2 1387 RGWFormatterFlusher& flusher, optional_yield y,
b3b6e05e 1388 const DoutPrefixProvider *dpp,
7c673cae
FG
1389 bool warnings_only)
1390{
1391 int ret = 0;
1392 const size_t max_entries =
1393 store->ctx()->_conf->rgw_list_buckets_max_chunk;
1394
1395 const size_t safe_max_objs_per_shard =
1396 store->ctx()->_conf->rgw_safe_max_objects_per_shard;
1397
1398 uint16_t shard_warn_pct =
1399 store->ctx()->_conf->rgw_shard_warning_threshold;
1400 if (shard_warn_pct > 100)
1401 shard_warn_pct = 90;
1402
1403 Formatter *formatter = flusher.get_formatter();
1404 flusher.start(0);
1405
1406 formatter->open_array_section("users");
1407
1408 for (const auto& user_id : user_ids) {
a8e16298 1409
7c673cae
FG
1410 formatter->open_object_section("user");
1411 formatter->dump_string("user_id", user_id);
7c673cae 1412 formatter->open_array_section("buckets");
a8e16298
TL
1413
1414 string marker;
9f95a23c 1415 rgw::sal::RGWBucketList buckets;
7c673cae 1416 do {
9f95a23c
TL
1417 rgw::sal::RGWRadosUser user(store, rgw_user(user_id));
1418
b3b6e05e 1419 ret = user.list_buckets(dpp, marker, string(), max_entries, false, buckets, y);
7c673cae 1420
7c673cae
FG
1421 if (ret < 0)
1422 return ret;
1423
f67539c2 1424 map<string, std::unique_ptr<rgw::sal::RGWBucket>>& m_buckets = buckets.get_buckets();
7c673cae
FG
1425
1426 for (const auto& iter : m_buckets) {
f67539c2 1427 auto& bucket = iter.second;
7c673cae
FG
1428 uint32_t num_shards = 1;
1429 uint64_t num_objects = 0;
1430
1431 /* need info for num_shards */
1432 RGWBucketInfo info;
7c673cae 1433
9f95a23c
TL
1434 marker = bucket->get_name(); /* Casey's location for marker update,
1435 * as we may now not reach the end of
1436 * the loop body */
7c673cae 1437
9f95a23c
TL
1438 ret = store->getRados()->get_bucket_info(store->svc(), bucket->get_tenant(),
1439 bucket->get_name(), info, nullptr,
b3b6e05e 1440 null_yield, dpp);
7c673cae
FG
1441 if (ret < 0)
1442 continue;
1443
1444 /* need stats for num_entries */
1445 string bucket_ver, master_ver;
1446 std::map<RGWObjCategory, RGWStorageStats> stats;
b3b6e05e 1447 ret = store->getRados()->get_bucket_stats(dpp, info, RGW_NO_SHARD, &bucket_ver,
7c673cae
FG
1448 &master_ver, stats, nullptr);
1449
1450 if (ret < 0)
1451 continue;
1452
1453 for (const auto& s : stats) {
adb31ebb 1454 num_objects += s.second.num_objects;
7c673cae
FG
1455 }
1456
f67539c2 1457 num_shards = info.layout.current_index.layout.normal.num_shards;
31f18b77
FG
1458 uint64_t objs_per_shard =
1459 (num_shards) ? num_objects/num_shards : num_objects;
7c673cae 1460 {
adb31ebb 1461 bool warn;
7c673cae 1462 stringstream ss;
adb31ebb
TL
1463 uint64_t fill_pct = objs_per_shard * 100 / safe_max_objs_per_shard;
1464 if (fill_pct > 100) {
1465 ss << "OVER " << fill_pct << "%";
1466 warn = true;
1467 } else if (fill_pct >= shard_warn_pct) {
1468 ss << "WARN " << fill_pct << "%";
1469 warn = true;
7c673cae 1470 } else {
adb31ebb
TL
1471 ss << "OK";
1472 warn = false;
7c673cae
FG
1473 }
1474
adb31ebb 1475 if (warn || !warnings_only) {
7c673cae 1476 formatter->open_object_section("bucket");
9f95a23c
TL
1477 formatter->dump_string("bucket", bucket->get_name());
1478 formatter->dump_string("tenant", bucket->get_tenant());
7c673cae
FG
1479 formatter->dump_int("num_objects", num_objects);
1480 formatter->dump_int("num_shards", num_shards);
1481 formatter->dump_int("objects_per_shard", objs_per_shard);
1482 formatter->dump_string("fill_status", ss.str());
1483 formatter->close_section();
1484 }
1485 }
1486 }
a8e16298 1487 formatter->flush(cout);
9f95a23c 1488 } while (buckets.is_truncated()); /* foreach: bucket */
7c673cae
FG
1489
1490 formatter->close_section();
1491 formatter->close_section();
1492 formatter->flush(cout);
1493
1494 } /* foreach: user_id */
1495
1496 formatter->close_section();
1497 formatter->flush(cout);
1498
1499 return ret;
1500} /* RGWBucketAdminOp::limit_check */
1501
f6b5b4d7
TL
1502int RGWBucketAdminOp::info(rgw::sal::RGWRadosStore *store,
1503 RGWBucketAdminOpState& op_state,
f67539c2 1504 RGWFormatterFlusher& flusher,
b3b6e05e
TL
1505 optional_yield y,
1506 const DoutPrefixProvider *dpp)
7c673cae 1507{
adb31ebb 1508 RGWBucket bucket;
11fdf7f2 1509 int ret = 0;
f6b5b4d7 1510 const std::string& bucket_name = op_state.get_bucket_name();
adb31ebb 1511 if (!bucket_name.empty()) {
b3b6e05e 1512 ret = bucket.init(store, op_state, null_yield, dpp);
adb31ebb
TL
1513 if (-ENOENT == ret)
1514 return -ERR_NO_SUCH_BUCKET;
1515 else if (ret < 0)
1516 return ret;
1517 }
1518
7c673cae
FG
1519 Formatter *formatter = flusher.get_formatter();
1520 flusher.start(0);
1521
1522 CephContext *cct = store->ctx();
1523
1524 const size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk;
1525
f6b5b4d7
TL
1526 const bool show_stats = op_state.will_fetch_stats();
1527 const rgw_user& user_id = op_state.get_user_id();
7c673cae
FG
1528 if (op_state.is_user_op()) {
1529 formatter->open_array_section("buckets");
1530
9f95a23c
TL
1531 rgw::sal::RGWBucketList buckets;
1532 rgw::sal::RGWRadosUser user(store, op_state.get_user_id());
f6b5b4d7
TL
1533 std::string marker;
1534 const std::string empty_end_marker;
1535 constexpr bool no_need_stats = false; // set need_stats to false
7c673cae
FG
1536
1537 do {
b3b6e05e 1538 ret = user.list_buckets(dpp, marker, empty_end_marker, max_entries,
f67539c2 1539 no_need_stats, buckets, y);
f6b5b4d7 1540 if (ret < 0) {
7c673cae 1541 return ret;
f6b5b4d7 1542 }
7c673cae 1543
f6b5b4d7 1544 const std::string* marker_cursor = nullptr;
f67539c2 1545 map<string, std::unique_ptr<rgw::sal::RGWBucket>>& m = buckets.get_buckets();
7c673cae 1546
f6b5b4d7
TL
1547 for (const auto& i : m) {
1548 const std::string& obj_name = i.first;
11fdf7f2
TL
1549 if (!bucket_name.empty() && bucket_name != obj_name) {
1550 continue;
1551 }
1552
f6b5b4d7 1553 if (show_stats) {
b3b6e05e 1554 bucket_stats(store, user_id.tenant, obj_name, formatter, dpp);
f6b5b4d7 1555 } else {
7c673cae 1556 formatter->dump_string("bucket", obj_name);
f6b5b4d7 1557 }
7c673cae 1558
f6b5b4d7
TL
1559 marker_cursor = &obj_name;
1560 } // for loop
1561 if (marker_cursor) {
1562 marker = *marker_cursor;
7c673cae
FG
1563 }
1564
1565 flusher.flush();
f6b5b4d7 1566 } while (buckets.is_truncated());
7c673cae
FG
1567
1568 formatter->close_section();
1569 } else if (!bucket_name.empty()) {
b3b6e05e 1570 ret = bucket_stats(store, user_id.tenant, bucket_name, formatter, dpp);
11fdf7f2
TL
1571 if (ret < 0) {
1572 return ret;
1573 }
7c673cae 1574 } else {
11fdf7f2
TL
1575 void *handle = nullptr;
1576 bool truncated = true;
7c673cae
FG
1577
1578 formatter->open_array_section("buckets");
b3b6e05e 1579 ret = store->ctl()->meta.mgr->list_keys_init(dpp, "bucket", &handle);
11fdf7f2
TL
1580 while (ret == 0 && truncated) {
1581 std::list<std::string> buckets;
f6b5b4d7 1582 constexpr int max_keys = 1000;
9f95a23c 1583 ret = store->ctl()->meta.mgr->list_keys_next(handle, max_keys, buckets,
f6b5b4d7 1584 &truncated);
11fdf7f2 1585 for (auto& bucket_name : buckets) {
f6b5b4d7 1586 if (show_stats) {
b3b6e05e 1587 bucket_stats(store, user_id.tenant, bucket_name, formatter, dpp);
f6b5b4d7 1588 } else {
11fdf7f2 1589 formatter->dump_string("bucket", bucket_name);
f6b5b4d7 1590 }
7c673cae
FG
1591 }
1592 }
e306af50 1593 store->ctl()->meta.mgr->list_keys_complete(handle);
7c673cae
FG
1594
1595 formatter->close_section();
1596 }
1597
1598 flusher.flush();
1599
1600 return 0;
1601}
1602
b3b6e05e 1603int RGWBucketAdminOp::set_quota(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp)
94b18763
FG
1604{
1605 RGWBucket bucket;
1606
b3b6e05e 1607 int ret = bucket.init(store, op_state, null_yield, dpp);
94b18763
FG
1608 if (ret < 0)
1609 return ret;
b3b6e05e 1610 return bucket.set_quota(op_state, dpp);
94b18763 1611}
7c673cae 1612
b3b6e05e 1613static int purge_bucket_instance(rgw::sal::RGWRadosStore *store, const RGWBucketInfo& bucket_info, const DoutPrefixProvider *dpp)
f64942e4 1614{
f67539c2 1615 int max_shards = (bucket_info.layout.current_index.layout.normal.num_shards > 0 ? bucket_info.layout.current_index.layout.normal.num_shards : 1);
f64942e4 1616 for (int i = 0; i < max_shards; i++) {
9f95a23c 1617 RGWRados::BucketShard bs(store->getRados());
f67539c2 1618 int shard_id = (bucket_info.layout.current_index.layout.normal.num_shards > 0 ? i : -1);
b3b6e05e 1619 int ret = bs.init(bucket_info.bucket, shard_id, bucket_info.layout.current_index, nullptr, dpp);
f64942e4
AA
1620 if (ret < 0) {
1621 cerr << "ERROR: bs.init(bucket=" << bucket_info.bucket << ", shard=" << shard_id
1622 << "): " << cpp_strerror(-ret) << std::endl;
1623 return ret;
1624 }
9f95a23c 1625 ret = store->getRados()->bi_remove(bs);
f64942e4
AA
1626 if (ret < 0) {
1627 cerr << "ERROR: failed to remove bucket index object: "
1628 << cpp_strerror(-ret) << std::endl;
1629 return ret;
1630 }
1631 }
1632 return 0;
1633}
1634
11fdf7f2 1635inline auto split_tenant(const std::string& bucket_name){
f64942e4
AA
1636 auto p = bucket_name.find('/');
1637 if(p != std::string::npos) {
1638 return std::make_pair(bucket_name.substr(0,p), bucket_name.substr(p+1));
1639 }
1640 return std::make_pair(std::string(), bucket_name);
1641}
1642
1643using bucket_instance_ls = std::vector<RGWBucketInfo>;
9f95a23c 1644void get_stale_instances(rgw::sal::RGWRadosStore *store, const std::string& bucket_name,
f64942e4 1645 const vector<std::string>& lst,
b3b6e05e
TL
1646 bucket_instance_ls& stale_instances,
1647 const DoutPrefixProvider *dpp)
f64942e4
AA
1648{
1649
9f95a23c 1650 auto obj_ctx = store->svc()->sysobj->init_obj_ctx();
f64942e4
AA
1651
1652 bucket_instance_ls other_instances;
1653// first iterate over the entries, and pick up the done buckets; these
1654// are guaranteed to be stale
1655 for (const auto& bucket_instance : lst){
1656 RGWBucketInfo binfo;
9f95a23c 1657 int r = store->getRados()->get_bucket_instance_info(obj_ctx, bucket_instance,
b3b6e05e 1658 binfo, nullptr,nullptr, null_yield, dpp);
f64942e4
AA
1659 if (r < 0){
1660 // this can only happen if someone deletes us right when we're processing
b3b6e05e 1661 ldpp_dout(dpp, -1) << "Bucket instance is invalid: " << bucket_instance
f64942e4
AA
1662 << cpp_strerror(-r) << dendl;
1663 continue;
1664 }
9f95a23c 1665 if (binfo.reshard_status == cls_rgw_reshard_status::DONE)
f64942e4
AA
1666 stale_instances.emplace_back(std::move(binfo));
1667 else {
1668 other_instances.emplace_back(std::move(binfo));
1669 }
1670 }
1671
1672 // Read the cur bucket info, if the bucket doesn't exist we can simply return
1673 // all the instances
11fdf7f2 1674 auto [tenant, bucket] = split_tenant(bucket_name);
f64942e4 1675 RGWBucketInfo cur_bucket_info;
b3b6e05e 1676 int r = store->getRados()->get_bucket_info(store->svc(), tenant, bucket, cur_bucket_info, nullptr, null_yield, dpp);
f64942e4
AA
1677 if (r < 0) {
1678 if (r == -ENOENT) {
1679 // bucket doesn't exist, everything is stale then
1680 stale_instances.insert(std::end(stale_instances),
1681 std::make_move_iterator(other_instances.begin()),
1682 std::make_move_iterator(other_instances.end()));
1683 } else {
1684 // all bets are off if we can't read the bucket, just return the sureshot stale instances
b3b6e05e 1685 ldpp_dout(dpp, -1) << "error: reading bucket info for bucket: "
f64942e4
AA
1686 << bucket << cpp_strerror(-r) << dendl;
1687 }
1688 return;
1689 }
1690
1691 // Don't process further in this round if bucket is resharding
9f95a23c 1692 if (cur_bucket_info.reshard_status == cls_rgw_reshard_status::IN_PROGRESS)
f64942e4
AA
1693 return;
1694
1695 other_instances.erase(std::remove_if(other_instances.begin(), other_instances.end(),
1696 [&cur_bucket_info](const RGWBucketInfo& b){
1697 return (b.bucket.bucket_id == cur_bucket_info.bucket.bucket_id ||
1698 b.bucket.bucket_id == cur_bucket_info.new_bucket_instance_id);
1699 }),
1700 other_instances.end());
1701
1702 // check if there are still instances left
1703 if (other_instances.empty()) {
1704 return;
1705 }
1706
1707 // Now we have a bucket with instances where the reshard status is none, this
1708 // usually happens when the reshard process couldn't complete, lockdown the
1709 // bucket and walk through these instances to make sure no one else interferes
1710 // with these
1711 {
1712 RGWBucketReshardLock reshard_lock(store, cur_bucket_info, true);
1713 r = reshard_lock.lock();
1714 if (r < 0) {
1715 // most likely bucket is under reshard, return the sureshot stale instances
b3b6e05e 1716 ldpp_dout(dpp, 5) << __func__
f64942e4
AA
1717 << "failed to take reshard lock; reshard underway likey" << dendl;
1718 return;
1719 }
1720 auto sg = make_scope_guard([&reshard_lock](){ reshard_lock.unlock();} );
1721 // this should be fast enough that we may not need to renew locks and check
1722 // exit status?, should we read the values of the instances again?
1723 stale_instances.insert(std::end(stale_instances),
1724 std::make_move_iterator(other_instances.begin()),
1725 std::make_move_iterator(other_instances.end()));
1726 }
1727
1728 return;
1729}
1730
9f95a23c 1731static int process_stale_instances(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
f64942e4 1732 RGWFormatterFlusher& flusher,
b3b6e05e 1733 const DoutPrefixProvider *dpp,
f64942e4
AA
1734 std::function<void(const bucket_instance_ls&,
1735 Formatter *,
9f95a23c 1736 rgw::sal::RGWRadosStore*)> process_f)
f64942e4
AA
1737{
1738 std::string marker;
1739 void *handle;
1740 Formatter *formatter = flusher.get_formatter();
1741 static constexpr auto default_max_keys = 1000;
1742
b3b6e05e 1743 int ret = store->ctl()->meta.mgr->list_keys_init(dpp, "bucket.instance", marker, &handle);
f64942e4
AA
1744 if (ret < 0) {
1745 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
1746 return ret;
1747 }
1748
1749 bool truncated;
1750
1751 formatter->open_array_section("keys");
e306af50
TL
1752 auto g = make_scope_guard([&store, &handle, &formatter]() {
1753 store->ctl()->meta.mgr->list_keys_complete(handle);
1754 formatter->close_section(); // keys
1755 formatter->flush(cout);
1756 });
f64942e4
AA
1757
1758 do {
1759 list<std::string> keys;
1760
9f95a23c 1761 ret = store->ctl()->meta.mgr->list_keys_next(handle, default_max_keys, keys, &truncated);
f64942e4
AA
1762 if (ret < 0 && ret != -ENOENT) {
1763 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
1764 return ret;
1765 } if (ret != -ENOENT) {
1766 // partition the list of buckets by buckets as the listing is un sorted,
1767 // since it would minimize the reads to bucket_info
1768 std::unordered_map<std::string, std::vector<std::string>> bucket_instance_map;
1769 for (auto &key: keys) {
1770 auto pos = key.find(':');
1771 if(pos != std::string::npos)
1772 bucket_instance_map[key.substr(0,pos)].emplace_back(std::move(key));
1773 }
1774 for (const auto& kv: bucket_instance_map) {
1775 bucket_instance_ls stale_lst;
b3b6e05e 1776 get_stale_instances(store, kv.first, kv.second, stale_lst, dpp);
f64942e4
AA
1777 process_f(stale_lst, formatter, store);
1778 }
1779 }
1780 } while (truncated);
1781
f64942e4
AA
1782 return 0;
1783}
1784
9f95a23c 1785int RGWBucketAdminOp::list_stale_instances(rgw::sal::RGWRadosStore *store,
f64942e4 1786 RGWBucketAdminOpState& op_state,
b3b6e05e
TL
1787 RGWFormatterFlusher& flusher,
1788 const DoutPrefixProvider *dpp)
f64942e4
AA
1789{
1790 auto process_f = [](const bucket_instance_ls& lst,
1791 Formatter *formatter,
9f95a23c 1792 rgw::sal::RGWRadosStore*){
f64942e4
AA
1793 for (const auto& binfo: lst)
1794 formatter->dump_string("key", binfo.bucket.get_key());
1795 };
b3b6e05e 1796 return process_stale_instances(store, op_state, flusher, dpp, process_f);
f64942e4
AA
1797}
1798
1799
9f95a23c 1800int RGWBucketAdminOp::clear_stale_instances(rgw::sal::RGWRadosStore *store,
f64942e4 1801 RGWBucketAdminOpState& op_state,
b3b6e05e
TL
1802 RGWFormatterFlusher& flusher,
1803 const DoutPrefixProvider *dpp)
f64942e4 1804{
b3b6e05e 1805 auto process_f = [dpp](const bucket_instance_ls& lst,
f64942e4 1806 Formatter *formatter,
b3b6e05e 1807 rgw::sal::RGWRadosStore *store) {
f64942e4 1808 for (const auto &binfo: lst) {
b3b6e05e 1809 int ret = purge_bucket_instance(store, binfo, dpp);
f64942e4
AA
1810 if (ret == 0){
1811 auto md_key = "bucket.instance:" + binfo.bucket.get_key();
b3b6e05e 1812 ret = store->ctl()->meta.mgr->remove(md_key, null_yield, dpp);
f64942e4
AA
1813 }
1814 formatter->open_object_section("delete_status");
1815 formatter->dump_string("bucket_instance", binfo.bucket.get_key());
1816 formatter->dump_int("status", -ret);
1817 formatter->close_section();
1818 }
1819 };
1820
b3b6e05e 1821 return process_stale_instances(store, op_state, flusher, dpp, process_f);
f64942e4
AA
1822}
1823
9f95a23c 1824static int fix_single_bucket_lc(rgw::sal::RGWRadosStore *store,
11fdf7f2 1825 const std::string& tenant_name,
b3b6e05e
TL
1826 const std::string& bucket_name,
1827 const DoutPrefixProvider *dpp)
11fdf7f2 1828{
11fdf7f2
TL
1829 RGWBucketInfo bucket_info;
1830 map <std::string, bufferlist> bucket_attrs;
9f95a23c 1831 int ret = store->getRados()->get_bucket_info(store->svc(), tenant_name, bucket_name,
b3b6e05e 1832 bucket_info, nullptr, null_yield, dpp, &bucket_attrs);
11fdf7f2
TL
1833 if (ret < 0) {
1834 // TODO: Should we handle the case where the bucket could've been removed between
1835 // listing and fetching?
1836 return ret;
1837 }
1838
b3b6e05e 1839 return rgw::lc::fix_lc_shard_entry(dpp, store, store->get_rgwlc()->get_lc(), bucket_info,
f67539c2 1840 bucket_attrs);
11fdf7f2
TL
1841}
1842
1843static void format_lc_status(Formatter* formatter,
1844 const std::string& tenant_name,
1845 const std::string& bucket_name,
1846 int status)
1847{
1848 formatter->open_object_section("bucket_entry");
1849 std::string entry = tenant_name.empty() ? bucket_name : tenant_name + "/" + bucket_name;
1850 formatter->dump_string("bucket", entry);
1851 formatter->dump_int("status", status);
1852 formatter->close_section(); // bucket_entry
1853}
1854
9f95a23c
TL
1855static void process_single_lc_entry(rgw::sal::RGWRadosStore *store,
1856 Formatter *formatter,
11fdf7f2 1857 const std::string& tenant_name,
b3b6e05e
TL
1858 const std::string& bucket_name,
1859 const DoutPrefixProvider *dpp)
11fdf7f2 1860{
b3b6e05e 1861 int ret = fix_single_bucket_lc(store, tenant_name, bucket_name, dpp);
11fdf7f2
TL
1862 format_lc_status(formatter, tenant_name, bucket_name, -ret);
1863}
1864
9f95a23c 1865int RGWBucketAdminOp::fix_lc_shards(rgw::sal::RGWRadosStore *store,
11fdf7f2 1866 RGWBucketAdminOpState& op_state,
b3b6e05e
TL
1867 RGWFormatterFlusher& flusher,
1868 const DoutPrefixProvider *dpp)
11fdf7f2
TL
1869{
1870 std::string marker;
1871 void *handle;
1872 Formatter *formatter = flusher.get_formatter();
1873 static constexpr auto default_max_keys = 1000;
1874
1875 bool truncated;
1876 if (const std::string& bucket_name = op_state.get_bucket_name();
1877 ! bucket_name.empty()) {
1878 const rgw_user user_id = op_state.get_user_id();
b3b6e05e 1879 process_single_lc_entry(store, formatter, user_id.tenant, bucket_name, dpp);
11fdf7f2
TL
1880 formatter->flush(cout);
1881 } else {
b3b6e05e 1882 int ret = store->ctl()->meta.mgr->list_keys_init(dpp, "bucket", marker, &handle);
11fdf7f2
TL
1883 if (ret < 0) {
1884 std::cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
1885 return ret;
1886 }
1887
1888 {
1889 formatter->open_array_section("lc_fix_status");
1890 auto sg = make_scope_guard([&store, &handle, &formatter](){
9f95a23c 1891 store->ctl()->meta.mgr->list_keys_complete(handle);
11fdf7f2
TL
1892 formatter->close_section(); // lc_fix_status
1893 formatter->flush(cout);
1894 });
1895 do {
1896 list<std::string> keys;
9f95a23c 1897 ret = store->ctl()->meta.mgr->list_keys_next(handle, default_max_keys, keys, &truncated);
11fdf7f2
TL
1898 if (ret < 0 && ret != -ENOENT) {
1899 std::cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
1900 return ret;
1901 } if (ret != -ENOENT) {
1902 for (const auto &key:keys) {
1903 auto [tenant_name, bucket_name] = split_tenant(key);
b3b6e05e 1904 process_single_lc_entry(store, formatter, tenant_name, bucket_name, dpp);
11fdf7f2
TL
1905 }
1906 }
1907 formatter->flush(cout); // regularly flush every 1k entries
1908 } while (truncated);
1909 }
1910
1911 }
1912 return 0;
1913
1914}
1915
b3b6e05e
TL
1916static bool has_object_expired(const DoutPrefixProvider *dpp,
1917 rgw::sal::RGWRadosStore *store,
9f95a23c 1918 const RGWBucketInfo& bucket_info,
81eedcae
TL
1919 const rgw_obj_key& key, utime_t& delete_at)
1920{
1921 rgw_obj obj(bucket_info.bucket, key);
1922 bufferlist delete_at_bl;
1923
b3b6e05e 1924 int ret = rgw_object_get_attr(dpp, store, bucket_info, obj, RGW_ATTR_DELETE_AT, delete_at_bl, null_yield);
81eedcae
TL
1925 if (ret < 0) {
1926 return false; // no delete at attr, proceed
1927 }
1928
1929 ret = decode_bl(delete_at_bl, delete_at);
1930 if (ret < 0) {
1931 return false; // failed to parse
1932 }
1933
1934 if (delete_at <= ceph_clock_now() && !delete_at.is_zero()) {
1935 return true;
1936 }
1937
1938 return false;
1939}
1940
b3b6e05e
TL
1941static int fix_bucket_obj_expiry(const DoutPrefixProvider *dpp,
1942 rgw::sal::RGWRadosStore *store,
9f95a23c 1943 const RGWBucketInfo& bucket_info,
81eedcae
TL
1944 RGWFormatterFlusher& flusher, bool dry_run)
1945{
1946 if (bucket_info.bucket.bucket_id == bucket_info.bucket.marker) {
b3b6e05e 1947 ldpp_dout(dpp, -1) << "Not a resharded bucket skipping" << dendl;
81eedcae
TL
1948 return 0; // not a resharded bucket, move along
1949 }
1950
1951 Formatter *formatter = flusher.get_formatter();
1952 formatter->open_array_section("expired_deletion_status");
1953 auto sg = make_scope_guard([&formatter] {
1954 formatter->close_section();
1955 formatter->flush(std::cout);
1956 });
1957
9f95a23c 1958 RGWRados::Bucket target(store->getRados(), bucket_info);
81eedcae
TL
1959 RGWRados::Bucket::List list_op(&target);
1960
1961 list_op.params.list_versions = bucket_info.versioned();
1962 list_op.params.allow_unordered = true;
1963
81eedcae
TL
1964 bool is_truncated {false};
1965 do {
1966 std::vector<rgw_bucket_dir_entry> objs;
1967
b3b6e05e 1968 int ret = list_op.list_objects(dpp, listing_max_entries, &objs, nullptr,
9f95a23c 1969 &is_truncated, null_yield);
81eedcae 1970 if (ret < 0) {
b3b6e05e 1971 ldpp_dout(dpp, -1) << "ERROR failed to list objects in the bucket" << dendl;
81eedcae
TL
1972 return ret;
1973 }
1974 for (const auto& obj : objs) {
1975 rgw_obj_key key(obj.key);
1976 utime_t delete_at;
b3b6e05e 1977 if (has_object_expired(dpp, store, bucket_info, key, delete_at)) {
81eedcae
TL
1978 formatter->open_object_section("object_status");
1979 formatter->dump_string("object", key.name);
1980 formatter->dump_stream("delete_at") << delete_at;
1981
1982 if (!dry_run) {
b3b6e05e 1983 ret = rgw_remove_object(dpp, store, bucket_info, bucket_info.bucket, key);
81eedcae
TL
1984 formatter->dump_int("status", ret);
1985 }
1986
1987 formatter->close_section(); // object_status
1988 }
1989 }
1990 formatter->flush(cout); // regularly flush every 1k entries
1991 } while (is_truncated);
1992
1993 return 0;
1994}
1995
9f95a23c
TL
1996int RGWBucketAdminOp::fix_obj_expiry(rgw::sal::RGWRadosStore *store,
1997 RGWBucketAdminOpState& op_state,
b3b6e05e
TL
1998 RGWFormatterFlusher& flusher,
1999 const DoutPrefixProvider *dpp, bool dry_run)
81eedcae
TL
2000{
2001 RGWBucket admin_bucket;
b3b6e05e 2002 int ret = admin_bucket.init(store, op_state, null_yield, dpp);
81eedcae 2003 if (ret < 0) {
b3b6e05e 2004 ldpp_dout(dpp, -1) << "failed to initialize bucket" << dendl;
81eedcae
TL
2005 return ret;
2006 }
2007
b3b6e05e 2008 return fix_bucket_obj_expiry(dpp, store, admin_bucket.get_bucket_info(), flusher, dry_run);
81eedcae
TL
2009}
2010
7c673cae
FG
2011void RGWBucketCompleteInfo::dump(Formatter *f) const {
2012 encode_json("bucket_info", info, f);
2013 encode_json("attrs", attrs, f);
2014}
2015
2016void RGWBucketCompleteInfo::decode_json(JSONObj *obj) {
2017 JSONDecoder::decode_json("bucket_info", info, obj);
2018 JSONDecoder::decode_json("attrs", attrs, obj);
2019}
2020
9f95a23c 2021class RGWBucketMetadataHandler : public RGWBucketMetadataHandlerBase {
7c673cae 2022public:
9f95a23c
TL
2023 struct Svc {
2024 RGWSI_Bucket *bucket{nullptr};
2025 } svc;
7c673cae 2026
9f95a23c
TL
2027 struct Ctl {
2028 RGWBucketCtl *bucket{nullptr};
2029 } ctl;
7c673cae 2030
9f95a23c 2031 RGWBucketMetadataHandler() {}
7c673cae 2032
9f95a23c
TL
2033 void init(RGWSI_Bucket *bucket_svc,
2034 RGWBucketCtl *bucket_ctl) override {
2035 base_init(bucket_svc->ctx(),
2036 bucket_svc->get_ep_be_handler().get());
2037 svc.bucket = bucket_svc;
2038 ctl.bucket = bucket_ctl;
2039 }
7c673cae 2040
9f95a23c 2041 string get_type() override { return "bucket"; }
7c673cae 2042
9f95a23c
TL
2043 RGWMetadataObject *get_meta_obj(JSONObj *jo, const obj_version& objv, const ceph::real_time& mtime) override {
2044 RGWBucketEntryPoint be;
7c673cae 2045
7c673cae 2046 try {
9f95a23c 2047 decode_json_obj(be, jo);
7c673cae 2048 } catch (JSONDecoder::err& e) {
9f95a23c 2049 return nullptr;
7c673cae
FG
2050 }
2051
9f95a23c
TL
2052 return new RGWBucketEntryMetadataObject(be, objv, mtime);
2053 }
7c673cae 2054
b3b6e05e 2055 int do_get(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWMetadataObject **obj, optional_yield y, const DoutPrefixProvider *dpp) override {
9f95a23c
TL
2056 RGWObjVersionTracker ot;
2057 RGWBucketEntryPoint be;
7c673cae 2058
9f95a23c
TL
2059 real_time mtime;
2060 map<string, bufferlist> attrs;
7c673cae 2061
9f95a23c 2062 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
7c673cae 2063
b3b6e05e 2064 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &ot, &mtime, &attrs, y, dpp);
7c673cae
FG
2065 if (ret < 0)
2066 return ret;
2067
9f95a23c 2068 RGWBucketEntryMetadataObject *mdo = new RGWBucketEntryMetadataObject(be, ot.read_version, mtime, std::move(attrs));
7c673cae 2069
9f95a23c
TL
2070 *obj = mdo;
2071
2072 return 0;
7c673cae
FG
2073 }
2074
9f95a23c
TL
2075 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2076 RGWMetadataObject *obj,
2077 RGWObjVersionTracker& objv_tracker,
2078 optional_yield y,
b3b6e05e 2079 const DoutPrefixProvider *dpp,
f67539c2 2080 RGWMDLogSyncType type, bool from_remote_zone) override;
7c673cae 2081
9f95a23c 2082 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
b3b6e05e 2083 optional_yield y, const DoutPrefixProvider *dpp) override {
7c673cae 2084 RGWBucketEntryPoint be;
7c673cae 2085
9f95a23c
TL
2086 real_time orig_mtime;
2087
2088 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
2089
b3b6e05e 2090 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &objv_tracker, &orig_mtime, nullptr, y, dpp);
7c673cae
FG
2091 if (ret < 0)
2092 return ret;
2093
2094 /*
31f18b77 2095 * We're unlinking the bucket but we don't want to update the entrypoint here - we're removing
7c673cae
FG
2096 * it immediately and don't want to invalidate our cached objv_version or the bucket obj removal
2097 * will incorrectly fail.
2098 */
b3b6e05e 2099 ret = ctl.bucket->unlink_bucket(be.owner, be.bucket, y, dpp, false);
7c673cae 2100 if (ret < 0) {
b3b6e05e 2101 ldpp_dout(dpp, -1) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
7c673cae
FG
2102 }
2103
b3b6e05e 2104 ret = svc.bucket->remove_bucket_entrypoint_info(ctx, entry, &objv_tracker, y, dpp);
7c673cae 2105 if (ret < 0) {
b3b6e05e 2106 ldpp_dout(dpp, -1) << "could not delete bucket=" << entry << dendl;
7c673cae
FG
2107 }
2108 /* idempotent */
2109 return 0;
2110 }
2111
9f95a23c
TL
2112 int call(std::function<int(RGWSI_Bucket_EP_Ctx& ctx)> f) {
2113 return call(nullopt, f);
7c673cae
FG
2114 }
2115
9f95a23c
TL
2116 int call(std::optional<RGWSI_MetaBackend_CtxParams> bectx_params,
2117 std::function<int(RGWSI_Bucket_EP_Ctx& ctx)> f) {
2118 return be_handler->call(bectx_params, [&](RGWSI_MetaBackend_Handler::Op *op) {
2119 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
2120 return f(ctx);
2121 });
2122 }
2123};
7c673cae 2124
9f95a23c
TL
2125class RGWMetadataHandlerPut_Bucket : public RGWMetadataHandlerPut_SObj
2126{
2127 RGWBucketMetadataHandler *bhandler;
2128 RGWBucketEntryMetadataObject *obj;
2129public:
2130 RGWMetadataHandlerPut_Bucket(RGWBucketMetadataHandler *_handler,
2131 RGWSI_MetaBackend_Handler::Op *op, string& entry,
2132 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
2133 optional_yield y,
f67539c2 2134 RGWMDLogSyncType type, bool from_remote_zone) : RGWMetadataHandlerPut_SObj(_handler, op, entry, obj, objv_tracker, y, type, from_remote_zone),
9f95a23c
TL
2135 bhandler(_handler) {
2136 obj = static_cast<RGWBucketEntryMetadataObject *>(_obj);
2137 }
2138 ~RGWMetadataHandlerPut_Bucket() {}
7c673cae 2139
9f95a23c
TL
2140 void encode_obj(bufferlist *bl) override {
2141 obj->get_ep().encode(*bl);
7c673cae
FG
2142 }
2143
b3b6e05e
TL
2144 int put_checked(const DoutPrefixProvider *dpp) override;
2145 int put_post(const DoutPrefixProvider *dpp) override;
9f95a23c 2146};
7c673cae 2147
9f95a23c
TL
2148int RGWBucketMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2149 RGWMetadataObject *obj,
2150 RGWObjVersionTracker& objv_tracker,
2151 optional_yield y,
b3b6e05e 2152 const DoutPrefixProvider *dpp,
f67539c2 2153 RGWMDLogSyncType type, bool from_remote_zone)
9f95a23c 2154{
f67539c2 2155 RGWMetadataHandlerPut_Bucket put_op(this, op, entry, obj, objv_tracker, y, type, from_remote_zone);
b3b6e05e 2156 return do_put_operate(&put_op, dpp);
9f95a23c 2157}
7c673cae 2158
b3b6e05e 2159int RGWMetadataHandlerPut_Bucket::put_checked(const DoutPrefixProvider *dpp)
9f95a23c
TL
2160{
2161 RGWBucketEntryMetadataObject *orig_obj = static_cast<RGWBucketEntryMetadataObject *>(old_obj);
7c673cae 2162
9f95a23c
TL
2163 if (orig_obj) {
2164 obj->set_pattrs(&orig_obj->get_attrs());
2165 }
7c673cae 2166
9f95a23c
TL
2167 auto& be = obj->get_ep();
2168 auto mtime = obj->get_mtime();
2169 auto pattrs = obj->get_pattrs();
7c673cae 2170
9f95a23c 2171 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
7c673cae 2172
9f95a23c
TL
2173 return bhandler->svc.bucket->store_bucket_entrypoint_info(ctx, entry,
2174 be,
2175 false,
2176 mtime,
2177 pattrs,
2178 &objv_tracker,
b3b6e05e
TL
2179 y,
2180 dpp);
9f95a23c 2181}
7c673cae 2182
b3b6e05e 2183int RGWMetadataHandlerPut_Bucket::put_post(const DoutPrefixProvider *dpp)
9f95a23c
TL
2184{
2185 auto& be = obj->get_ep();
7c673cae 2186
9f95a23c 2187 int ret;
7c673cae 2188
9f95a23c
TL
2189 /* link bucket */
2190 if (be.linked) {
b3b6e05e 2191 ret = bhandler->ctl.bucket->link_bucket(be.owner, be.bucket, be.creation_time, y, dpp, false);
9f95a23c 2192 } else {
b3b6e05e 2193 ret = bhandler->ctl.bucket->unlink_bucket(be.owner, be.bucket, y, dpp, false);
7c673cae 2194 }
181888fb 2195
9f95a23c
TL
2196 return ret;
2197}
7c673cae 2198
9f95a23c 2199static void get_md5_digest(const RGWBucketEntryPoint *be, string& md5_digest) {
11fdf7f2
TL
2200
2201 char md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
2202 unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
2203 bufferlist bl;
2204
2205 Formatter *f = new JSONFormatter(false);
2206 be->dump(f);
2207 f->flush(bl);
2208
2209 MD5 hash;
2210 hash.Update((const unsigned char *)bl.c_str(), bl.length());
2211 hash.Final(m);
2212
2213 buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, md5);
2214
2215 delete f;
2216
2217 md5_digest = md5;
2218}
2219
2220#define ARCHIVE_META_ATTR RGW_ATTR_PREFIX "zone.archive.info"
2221
2222struct archive_meta_info {
2223 rgw_bucket orig_bucket;
2224
2225 bool from_attrs(CephContext *cct, map<string, bufferlist>& attrs) {
2226 auto iter = attrs.find(ARCHIVE_META_ATTR);
2227 if (iter == attrs.end()) {
2228 return false;
2229 }
2230
2231 auto bliter = iter->second.cbegin();
2232 try {
2233 decode(bliter);
2234 } catch (buffer::error& err) {
2235 ldout(cct, 0) << "ERROR: failed to decode archive meta info" << dendl;
2236 return false;
2237 }
2238
2239 return true;
2240 }
2241
2242 void store_in_attrs(map<string, bufferlist>& attrs) const {
2243 encode(attrs[ARCHIVE_META_ATTR]);
2244 }
2245
2246 void encode(bufferlist& bl) const {
2247 ENCODE_START(1, 1, bl);
2248 encode(orig_bucket, bl);
2249 ENCODE_FINISH(bl);
2250 }
2251
2252 void decode(bufferlist::const_iterator& bl) {
2253 DECODE_START(1, bl);
2254 decode(orig_bucket, bl);
2255 DECODE_FINISH(bl);
2256 }
2257};
2258WRITE_CLASS_ENCODER(archive_meta_info)
2259
2260class RGWArchiveBucketMetadataHandler : public RGWBucketMetadataHandler {
2261public:
9f95a23c
TL
2262 RGWArchiveBucketMetadataHandler() {}
2263
2264 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
b3b6e05e 2265 optional_yield y, const DoutPrefixProvider *dpp) override {
9f95a23c
TL
2266 auto cct = svc.bucket->ctx();
2267
2268 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
2269
b3b6e05e 2270 ldpp_dout(dpp, 5) << "SKIP: bucket removal is not allowed on archive zone: bucket:" << entry << " ... proceeding to rename" << dendl;
11fdf7f2
TL
2271
2272 string tenant_name, bucket_name;
2273 parse_bucket(entry, &tenant_name, &bucket_name);
9f95a23c
TL
2274 rgw_bucket entry_bucket;
2275 entry_bucket.tenant = tenant_name;
2276 entry_bucket.name = bucket_name;
11fdf7f2
TL
2277
2278 real_time mtime;
2279
2280 /* read original entrypoint */
2281
2282 RGWBucketEntryPoint be;
11fdf7f2 2283 map<string, bufferlist> attrs;
b3b6e05e 2284 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &objv_tracker, &mtime, &attrs, y, dpp);
11fdf7f2
TL
2285 if (ret < 0) {
2286 return ret;
2287 }
2288
9f95a23c 2289 string bi_meta_name = RGWSI_Bucket::get_bi_meta_key(be.bucket);
11fdf7f2
TL
2290
2291 /* read original bucket instance info */
2292
2293 map<string, bufferlist> attrs_m;
2294 ceph::real_time orig_mtime;
2295 RGWBucketInfo old_bi;
2296
b3b6e05e 2297 ret = ctl.bucket->read_bucket_instance_info(be.bucket, &old_bi, y, dpp, RGWBucketCtl::BucketInstance::GetParams()
9f95a23c
TL
2298 .set_mtime(&orig_mtime)
2299 .set_attrs(&attrs_m));
11fdf7f2
TL
2300 if (ret < 0) {
2301 return ret;
2302 }
2303
2304 archive_meta_info ami;
2305
9f95a23c 2306 if (!ami.from_attrs(svc.bucket->ctx(), attrs_m)) {
11fdf7f2
TL
2307 ami.orig_bucket = old_bi.bucket;
2308 ami.store_in_attrs(attrs_m);
2309 }
2310
2311 /* generate a new bucket instance. We could have avoided this if we could just point a new
2312 * bucket entry point to the old bucket instance, however, due to limitation in the way
2313 * we index buckets under the user, bucket entrypoint and bucket instance of the same
2314 * bucket need to have the same name, so we need to copy the old bucket instance into
2315 * to a new entry with the new name
2316 */
2317
2318 string new_bucket_name;
2319
2320 RGWBucketInfo new_bi = old_bi;
2321 RGWBucketEntryPoint new_be = be;
2322
2323 string md5_digest;
2324
2325 get_md5_digest(&new_be, md5_digest);
2326 new_bucket_name = ami.orig_bucket.name + "-deleted-" + md5_digest;
2327
2328 new_bi.bucket.name = new_bucket_name;
2329 new_bi.objv_tracker.clear();
2330
2331 new_be.bucket.name = new_bucket_name;
2332
b3b6e05e 2333 ret = ctl.bucket->store_bucket_instance_info(be.bucket, new_bi, y, dpp, RGWBucketCtl::BucketInstance::PutParams()
9f95a23c
TL
2334 .set_exclusive(false)
2335 .set_mtime(orig_mtime)
2336 .set_attrs(&attrs_m)
2337 .set_orig_info(&old_bi));
11fdf7f2 2338 if (ret < 0) {
b3b6e05e 2339 ldpp_dout(dpp, 0) << "ERROR: failed to put new bucket instance info for bucket=" << new_bi.bucket << " ret=" << ret << dendl;
11fdf7f2
TL
2340 return ret;
2341 }
2342
2343 /* store a new entrypoint */
2344
2345 RGWObjVersionTracker ot;
9f95a23c 2346 ot.generate_new_write_ver(cct);
11fdf7f2 2347
9f95a23c 2348 ret = svc.bucket->store_bucket_entrypoint_info(ctx, RGWSI_Bucket::get_entrypoint_meta_key(new_be.bucket),
b3b6e05e 2349 new_be, true, mtime, &attrs, nullptr, y, dpp);
11fdf7f2 2350 if (ret < 0) {
b3b6e05e 2351 ldpp_dout(dpp, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be.bucket << " ret=" << ret << dendl;
11fdf7f2
TL
2352 return ret;
2353 }
2354
2355 /* link new bucket */
2356
b3b6e05e 2357 ret = ctl.bucket->link_bucket(new_be.owner, new_be.bucket, new_be.creation_time, y, dpp, false);
11fdf7f2 2358 if (ret < 0) {
b3b6e05e 2359 ldpp_dout(dpp, 0) << "ERROR: failed to link new bucket for bucket=" << new_be.bucket << " ret=" << ret << dendl;
11fdf7f2
TL
2360 return ret;
2361 }
2362
2363 /* clean up old stuff */
2364
b3b6e05e 2365 ret = ctl.bucket->unlink_bucket(be.owner, entry_bucket, y, dpp, false);
11fdf7f2 2366 if (ret < 0) {
b3b6e05e 2367 ldpp_dout(dpp, -1) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
11fdf7f2
TL
2368 }
2369
2370 // if (ret == -ECANCELED) it means that there was a race here, and someone
2371 // wrote to the bucket entrypoint just before we removed it. The question is
2372 // whether it was a newly created bucket entrypoint ... in which case we
2373 // should ignore the error and move forward, or whether it is a higher version
2374 // of the same bucket instance ... in which we should retry
9f95a23c
TL
2375 ret = svc.bucket->remove_bucket_entrypoint_info(ctx,
2376 RGWSI_Bucket::get_entrypoint_meta_key(be.bucket),
2377 &objv_tracker,
b3b6e05e
TL
2378 y,
2379 dpp);
9f95a23c 2380 if (ret < 0) {
b3b6e05e 2381 ldpp_dout(dpp, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be.bucket << " ret=" << ret << dendl;
9f95a23c
TL
2382 return ret;
2383 }
2384
b3b6e05e 2385 ret = ctl.bucket->remove_bucket_instance_info(be.bucket, old_bi, y, dpp);
11fdf7f2 2386 if (ret < 0) {
b3b6e05e 2387 ldpp_dout(dpp, -1) << "could not delete bucket=" << entry << dendl;
11fdf7f2
TL
2388 }
2389
11fdf7f2
TL
2390
2391 /* idempotent */
2392
2393 return 0;
2394 }
2395
9f95a23c
TL
2396 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2397 RGWMetadataObject *obj,
2398 RGWObjVersionTracker& objv_tracker,
b3b6e05e 2399 optional_yield y, const DoutPrefixProvider *dpp,
f67539c2 2400 RGWMDLogSyncType type, bool from_remote_zone) override {
11fdf7f2
TL
2401 if (entry.find("-deleted-") != string::npos) {
2402 RGWObjVersionTracker ot;
2403 RGWMetadataObject *robj;
b3b6e05e 2404 int ret = do_get(op, entry, &robj, y, dpp);
11fdf7f2
TL
2405 if (ret != -ENOENT) {
2406 if (ret < 0) {
2407 return ret;
2408 }
2409 ot.read_version = robj->get_version();
2410 delete robj;
2411
b3b6e05e 2412 ret = do_remove(op, entry, ot, y, dpp);
11fdf7f2
TL
2413 if (ret < 0) {
2414 return ret;
2415 }
2416 }
2417 }
2418
9f95a23c 2419 return RGWBucketMetadataHandler::do_put(op, entry, obj,
b3b6e05e 2420 objv_tracker, y, dpp, type, from_remote_zone);
11fdf7f2
TL
2421 }
2422
2423};
2424
9f95a23c
TL
2425class RGWBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandlerBase {
2426 int read_bucket_instance_entry(RGWSI_Bucket_BI_Ctx& ctx,
2427 const string& entry,
2428 RGWBucketCompleteInfo *bi,
2429 ceph::real_time *pmtime,
b3b6e05e
TL
2430 optional_yield y,
2431 const DoutPrefixProvider *dpp) {
9f95a23c
TL
2432 return svc.bucket->read_bucket_instance_info(ctx,
2433 entry,
2434 &bi->info,
2435 pmtime, &bi->attrs,
b3b6e05e
TL
2436 y,
2437 dpp);
9f95a23c 2438 }
7c673cae
FG
2439
2440public:
9f95a23c
TL
2441 struct Svc {
2442 RGWSI_Zone *zone{nullptr};
2443 RGWSI_Bucket *bucket{nullptr};
2444 RGWSI_BucketIndex *bi{nullptr};
2445 } svc;
2446
2447 RGWBucketInstanceMetadataHandler() {}
2448
2449 void init(RGWSI_Zone *zone_svc,
f67539c2
TL
2450 RGWSI_Bucket *bucket_svc,
2451 RGWSI_BucketIndex *bi_svc) override {
9f95a23c
TL
2452 base_init(bucket_svc->ctx(),
2453 bucket_svc->get_bi_be_handler().get());
2454 svc.zone = zone_svc;
2455 svc.bucket = bucket_svc;
2456 svc.bi = bi_svc;
2457 }
2458
7c673cae
FG
2459 string get_type() override { return "bucket.instance"; }
2460
9f95a23c 2461 RGWMetadataObject *get_meta_obj(JSONObj *jo, const obj_version& objv, const ceph::real_time& mtime) override {
7c673cae
FG
2462 RGWBucketCompleteInfo bci;
2463
9f95a23c
TL
2464 try {
2465 decode_json_obj(bci, jo);
2466 } catch (JSONDecoder::err& e) {
2467 return nullptr;
2468 }
2469
2470 return new RGWBucketInstanceMetadataObject(bci, objv, mtime);
2471 }
2472
b3b6e05e 2473 int do_get(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWMetadataObject **obj, optional_yield y, const DoutPrefixProvider *dpp) override {
9f95a23c 2474 RGWBucketCompleteInfo bci;
7c673cae 2475 real_time mtime;
7c673cae 2476
9f95a23c
TL
2477 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2478
b3b6e05e 2479 int ret = svc.bucket->read_bucket_instance_info(ctx, entry, &bci.info, &mtime, &bci.attrs, y, dpp);
7c673cae
FG
2480 if (ret < 0)
2481 return ret;
2482
2483 RGWBucketInstanceMetadataObject *mdo = new RGWBucketInstanceMetadataObject(bci, bci.info.objv_tracker.read_version, mtime);
2484
2485 *obj = mdo;
2486
2487 return 0;
2488 }
2489
9f95a23c
TL
2490 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2491 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
b3b6e05e 2492 optional_yield y, const DoutPrefixProvider *dpp,
f67539c2 2493 RGWMDLogSyncType sync_type, bool from_remote_zone) override;
7c673cae 2494
9f95a23c 2495 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
b3b6e05e 2496 optional_yield y, const DoutPrefixProvider *dpp) override {
9f95a23c 2497 RGWBucketCompleteInfo bci;
7c673cae 2498
9f95a23c
TL
2499 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2500
b3b6e05e 2501 int ret = read_bucket_instance_entry(ctx, entry, &bci, nullptr, y, dpp);
9f95a23c 2502 if (ret < 0 && ret != -ENOENT)
7c673cae
FG
2503 return ret;
2504
b3b6e05e 2505 return svc.bucket->remove_bucket_instance_info(ctx, entry, bci.info, &bci.info.objv_tracker, y, dpp);
9f95a23c 2506 }
7c673cae 2507
9f95a23c
TL
2508 int call(std::function<int(RGWSI_Bucket_BI_Ctx& ctx)> f) {
2509 return call(nullopt, f);
2510 }
c07f9fc5 2511
9f95a23c
TL
2512 int call(std::optional<RGWSI_MetaBackend_CtxParams> bectx_params,
2513 std::function<int(RGWSI_Bucket_BI_Ctx& ctx)> f) {
2514 return be_handler->call(bectx_params, [&](RGWSI_MetaBackend_Handler::Op *op) {
2515 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2516 return f(ctx);
2517 });
2518 }
2519};
c07f9fc5 2520
9f95a23c
TL
2521class RGWMetadataHandlerPut_BucketInstance : public RGWMetadataHandlerPut_SObj
2522{
2523 CephContext *cct;
2524 RGWBucketInstanceMetadataHandler *bihandler;
2525 RGWBucketInstanceMetadataObject *obj;
2526public:
f67539c2 2527 RGWMetadataHandlerPut_BucketInstance(CephContext *_cct,
9f95a23c
TL
2528 RGWBucketInstanceMetadataHandler *_handler,
2529 RGWSI_MetaBackend_Handler::Op *_op, string& entry,
2530 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
2531 optional_yield y,
f67539c2
TL
2532 RGWMDLogSyncType type, bool from_remote_zone) : RGWMetadataHandlerPut_SObj(_handler, _op, entry, obj, objv_tracker, y, type, from_remote_zone),
2533 cct(_cct), bihandler(_handler) {
9f95a23c 2534 obj = static_cast<RGWBucketInstanceMetadataObject *>(_obj);
c07f9fc5 2535
9f95a23c
TL
2536 auto& bci = obj->get_bci();
2537 obj->set_pattrs(&bci.attrs);
2538 }
7c673cae 2539
9f95a23c
TL
2540 void encode_obj(bufferlist *bl) override {
2541 obj->get_bucket_info().encode(*bl);
2542 }
7c673cae 2543
b3b6e05e
TL
2544 int put_check(const DoutPrefixProvider *dpp) override;
2545 int put_checked(const DoutPrefixProvider *dpp) override;
2546 int put_post(const DoutPrefixProvider *dpp) override;
9f95a23c 2547};
7c673cae 2548
9f95a23c
TL
2549int RGWBucketInstanceMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op,
2550 string& entry,
2551 RGWMetadataObject *obj,
2552 RGWObjVersionTracker& objv_tracker,
2553 optional_yield y,
b3b6e05e 2554 const DoutPrefixProvider *dpp,
f67539c2 2555 RGWMDLogSyncType type, bool from_remote_zone)
9f95a23c
TL
2556{
2557 RGWMetadataHandlerPut_BucketInstance put_op(svc.bucket->ctx(), this, op, entry, obj,
f67539c2 2558 objv_tracker, y, type, from_remote_zone);
b3b6e05e 2559 return do_put_operate(&put_op, dpp);
9f95a23c 2560}
7c673cae 2561
f67539c2
TL
2562void init_default_bucket_layout(CephContext *cct, rgw::BucketLayout& layout,
2563 const RGWZone& zone,
2564 std::optional<uint32_t> shards,
2565 std::optional<rgw::BucketIndexType> type) {
2566 layout.current_index.gen = 0;
2567 layout.current_index.layout.normal.hash_type = rgw::BucketHashType::Mod;
2568
2569 layout.current_index.layout.type =
2570 type.value_or(rgw::BucketIndexType::Normal);
2571
2572 if (shards) {
2573 layout.current_index.layout.normal.num_shards = *shards;
2574 } else if (cct->_conf->rgw_override_bucket_index_max_shards > 0) {
2575 layout.current_index.layout.normal.num_shards =
2576 cct->_conf->rgw_override_bucket_index_max_shards;
2577 } else {
2578 layout.current_index.layout.normal.num_shards =
2579 zone.bucket_index_max_shards;
2580 }
2581
2582 if (layout.current_index.layout.type == rgw::BucketIndexType::Normal) {
2583 layout.logs.push_back(log_layout_from_index(
2584 layout.current_index.gen,
2585 layout.current_index.layout.normal));
2586 }
2587}
2588
b3b6e05e 2589int RGWMetadataHandlerPut_BucketInstance::put_check(const DoutPrefixProvider *dpp)
9f95a23c
TL
2590{
2591 int ret;
7c673cae 2592
9f95a23c 2593 RGWBucketCompleteInfo& bci = obj->get_bci();
7c673cae 2594
9f95a23c 2595 RGWBucketInstanceMetadataObject *orig_obj = static_cast<RGWBucketInstanceMetadataObject *>(old_obj);
7c673cae 2596
9f95a23c 2597 RGWBucketCompleteInfo *old_bci = (orig_obj ? &orig_obj->get_bci() : nullptr);
7c673cae 2598
f67539c2
TL
2599 const bool exists = (!!orig_obj);
2600
2601 if (from_remote_zone) {
2602 // don't sync bucket layout changes
2603 if (!exists) {
2604 auto& bci_index = bci.info.layout.current_index.layout;
2605 auto index_type = bci_index.type;
2606 auto num_shards = bci_index.normal.num_shards;
2607 init_default_bucket_layout(cct, bci.info.layout,
2608 bihandler->svc.zone->get_zone(),
2609 num_shards, index_type);
2610 } else {
2611 bci.info.layout = old_bci->info.layout;
2612 }
2613 }
7c673cae 2614
9f95a23c
TL
2615 if (!exists || old_bci->info.bucket.bucket_id != bci.info.bucket.bucket_id) {
2616 /* a new bucket, we need to select a new bucket placement for it */
2617 string tenant_name;
2618 string bucket_name;
2619 string bucket_instance;
2620 parse_bucket(entry, &tenant_name, &bucket_name, &bucket_instance);
7c673cae 2621
9f95a23c
TL
2622 RGWZonePlacementInfo rule_info;
2623 bci.info.bucket.name = bucket_name;
2624 bci.info.bucket.bucket_id = bucket_instance;
2625 bci.info.bucket.tenant = tenant_name;
2626 // if the sync module never writes data, don't require the zone to specify all placement targets
2627 if (bihandler->svc.zone->sync_module_supports_writes()) {
b3b6e05e 2628 ret = bihandler->svc.zone->select_bucket_location_by_rule(dpp, bci.info.placement_rule, &rule_info, y);
9f95a23c 2629 if (ret < 0) {
b3b6e05e 2630 ldpp_dout(dpp, 0) << "ERROR: select_bucket_placement() returned " << ret << dendl;
9f95a23c
TL
2631 return ret;
2632 }
2633 }
f67539c2 2634 bci.info.layout.current_index.layout.type = rule_info.index_type;
9f95a23c
TL
2635 } else {
2636 /* existing bucket, keep its placement */
2637 bci.info.bucket.explicit_placement = old_bci->info.bucket.explicit_placement;
2638 bci.info.placement_rule = old_bci->info.placement_rule;
7c673cae
FG
2639 }
2640
9f95a23c
TL
2641 /* record the read version (if any), store the new version */
2642 bci.info.objv_tracker.read_version = objv_tracker.read_version;
2643 bci.info.objv_tracker.write_version = objv_tracker.write_version;
7c673cae 2644
9f95a23c
TL
2645 return 0;
2646}
7c673cae 2647
b3b6e05e 2648int RGWMetadataHandlerPut_BucketInstance::put_checked(const DoutPrefixProvider *dpp)
9f95a23c
TL
2649{
2650 RGWBucketInstanceMetadataObject *orig_obj = static_cast<RGWBucketInstanceMetadataObject *>(old_obj);
7c673cae 2651
9f95a23c 2652 RGWBucketInfo *orig_info = (orig_obj ? &orig_obj->get_bucket_info() : nullptr);
7c673cae 2653
9f95a23c
TL
2654 auto& info = obj->get_bucket_info();
2655 auto mtime = obj->get_mtime();
2656 auto pattrs = obj->get_pattrs();
7c673cae 2657
9f95a23c 2658 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
7c673cae 2659
9f95a23c
TL
2660 return bihandler->svc.bucket->store_bucket_instance_info(ctx,
2661 entry,
2662 info,
2663 orig_info,
2664 false,
2665 mtime,
2666 pattrs,
b3b6e05e
TL
2667 y,
2668 dpp);
9f95a23c 2669}
7c673cae 2670
b3b6e05e 2671int RGWMetadataHandlerPut_BucketInstance::put_post(const DoutPrefixProvider *dpp)
9f95a23c
TL
2672{
2673 RGWBucketCompleteInfo& bci = obj->get_bci();
7c673cae 2674
9f95a23c 2675 objv_tracker = bci.info.objv_tracker;
7c673cae 2676
b3b6e05e 2677 int ret = bihandler->svc.bi->init_index(dpp, bci.info);
9f95a23c
TL
2678 if (ret < 0) {
2679 return ret;
2680 }
2681
2682 return STATUS_APPLIED;
2683}
7c673cae 2684
9f95a23c
TL
2685class RGWArchiveBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandler {
2686public:
2687 RGWArchiveBucketInstanceMetadataHandler() {}
7c673cae 2688
b3b6e05e
TL
2689 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) override {
2690 ldpp_dout(dpp, 0) << "SKIP: bucket instance removal is not allowed on archive zone: bucket.instance:" << entry << dendl;
9f95a23c
TL
2691 return 0;
2692 }
2693};
2694
9f95a23c
TL
2695RGWBucketCtl::RGWBucketCtl(RGWSI_Zone *zone_svc,
2696 RGWSI_Bucket *bucket_svc,
2697 RGWSI_Bucket_Sync *bucket_sync_svc,
f67539c2 2698 RGWSI_BucketIndex *bi_svc) : cct(zone_svc->ctx())
9f95a23c
TL
2699{
2700 svc.zone = zone_svc;
2701 svc.bucket = bucket_svc;
2702 svc.bucket_sync = bucket_sync_svc;
2703 svc.bi = bi_svc;
2704}
2705
2706void RGWBucketCtl::init(RGWUserCtl *user_ctl,
2707 RGWBucketMetadataHandler *_bm_handler,
2708 RGWBucketInstanceMetadataHandler *_bmi_handler,
b3b6e05e
TL
2709 RGWDataChangesLog *datalog,
2710 const DoutPrefixProvider *dpp)
9f95a23c
TL
2711{
2712 ctl.user = user_ctl;
2713
2714 bm_handler = _bm_handler;
2715 bmi_handler = _bmi_handler;
2716
2717 bucket_be_handler = bm_handler->get_be_handler();
2718 bi_be_handler = bmi_handler->get_be_handler();
2719
f67539c2 2720 datalog->set_bucket_filter(
b3b6e05e
TL
2721 [this](const rgw_bucket& bucket, optional_yield y, const DoutPrefixProvider *dpp) {
2722 return bucket_exports_data(bucket, y, dpp);
f67539c2 2723 });
9f95a23c
TL
2724}
2725
2726int RGWBucketCtl::call(std::function<int(RGWSI_Bucket_X_Ctx& ctx)> f) {
2727 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ep_ctx) {
2728 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& bi_ctx) {
2729 RGWSI_Bucket_X_Ctx ctx{ep_ctx, bi_ctx};
2730 return f(ctx);
2731 });
2732 });
2733}
2734
2735int RGWBucketCtl::read_bucket_entrypoint_info(const rgw_bucket& bucket,
2736 RGWBucketEntryPoint *info,
b3b6e05e 2737 optional_yield y, const DoutPrefixProvider *dpp,
9f95a23c
TL
2738 const Bucket::GetParams& params)
2739{
2740 return bm_handler->call(params.bectx_params, [&](RGWSI_Bucket_EP_Ctx& ctx) {
2741 return svc.bucket->read_bucket_entrypoint_info(ctx,
2742 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2743 info,
2744 params.objv_tracker,
2745 params.mtime,
2746 params.attrs,
2747 y,
b3b6e05e 2748 dpp,
9f95a23c
TL
2749 params.cache_info,
2750 params.refresh_version);
2751 });
2752}
2753
2754int RGWBucketCtl::store_bucket_entrypoint_info(const rgw_bucket& bucket,
2755 RGWBucketEntryPoint& info,
2756 optional_yield y,
b3b6e05e 2757 const DoutPrefixProvider *dpp,
9f95a23c
TL
2758 const Bucket::PutParams& params)
2759{
2760 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
2761 return svc.bucket->store_bucket_entrypoint_info(ctx,
2762 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2763 info,
2764 params.exclusive,
2765 params.mtime,
2766 params.attrs,
2767 params.objv_tracker,
b3b6e05e
TL
2768 y,
2769 dpp);
9f95a23c
TL
2770 });
2771}
2772
2773int RGWBucketCtl::remove_bucket_entrypoint_info(const rgw_bucket& bucket,
2774 optional_yield y,
b3b6e05e 2775 const DoutPrefixProvider *dpp,
9f95a23c
TL
2776 const Bucket::RemoveParams& params)
2777{
2778 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
2779 return svc.bucket->remove_bucket_entrypoint_info(ctx,
2780 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2781 params.objv_tracker,
b3b6e05e
TL
2782 y,
2783 dpp);
9f95a23c
TL
2784 });
2785}
2786
2787int RGWBucketCtl::read_bucket_instance_info(const rgw_bucket& bucket,
2788 RGWBucketInfo *info,
2789 optional_yield y,
b3b6e05e 2790 const DoutPrefixProvider *dpp,
9f95a23c
TL
2791 const BucketInstance::GetParams& params)
2792{
2793 int ret = bmi_handler->call(params.bectx_params, [&](RGWSI_Bucket_BI_Ctx& ctx) {
2794 return svc.bucket->read_bucket_instance_info(ctx,
2795 RGWSI_Bucket::get_bi_meta_key(bucket),
2796 info,
2797 params.mtime,
2798 params.attrs,
2799 y,
b3b6e05e 2800 dpp,
9f95a23c
TL
2801 params.cache_info,
2802 params.refresh_version);
2803 });
2804
2805 if (ret < 0) {
2806 return ret;
2807 }
2808
2809 if (params.objv_tracker) {
2810 *params.objv_tracker = info->objv_tracker;
2811 }
2812
2813 return 0;
2814}
2815
2816int RGWBucketCtl::read_bucket_info(const rgw_bucket& bucket,
2817 RGWBucketInfo *info,
2818 optional_yield y,
b3b6e05e 2819 const DoutPrefixProvider *dpp,
9f95a23c
TL
2820 const BucketInstance::GetParams& params,
2821 RGWObjVersionTracker *ep_objv_tracker)
2822{
2823 const rgw_bucket *b = &bucket;
2824
2825 std::optional<RGWBucketEntryPoint> ep;
2826
2827 if (b->bucket_id.empty()) {
2828 ep.emplace();
2829
b3b6e05e 2830 int r = read_bucket_entrypoint_info(*b, &(*ep), y, dpp, RGWBucketCtl::Bucket::GetParams()
9f95a23c
TL
2831 .set_bectx_params(params.bectx_params)
2832 .set_objv_tracker(ep_objv_tracker));
2833 if (r < 0) {
2834 return r;
7c673cae
FG
2835 }
2836
9f95a23c
TL
2837 b = &ep->bucket;
2838 }
2839
2840 int ret = bmi_handler->call(params.bectx_params, [&](RGWSI_Bucket_BI_Ctx& ctx) {
2841 return svc.bucket->read_bucket_instance_info(ctx,
2842 RGWSI_Bucket::get_bi_meta_key(*b),
2843 info,
2844 params.mtime,
2845 params.attrs,
b3b6e05e 2846 y, dpp,
9f95a23c
TL
2847 params.cache_info,
2848 params.refresh_version);
2849 });
2850
2851 if (ret < 0) {
2852 return ret;
2853 }
2854
2855 if (params.objv_tracker) {
2856 *params.objv_tracker = info->objv_tracker;
2857 }
2858
2859 return 0;
2860}
2861
2862int RGWBucketCtl::do_store_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
2863 const rgw_bucket& bucket,
2864 RGWBucketInfo& info,
2865 optional_yield y,
b3b6e05e 2866 const DoutPrefixProvider *dpp,
9f95a23c
TL
2867 const BucketInstance::PutParams& params)
2868{
2869 if (params.objv_tracker) {
2870 info.objv_tracker = *params.objv_tracker;
2871 }
2872
2873 return svc.bucket->store_bucket_instance_info(ctx,
2874 RGWSI_Bucket::get_bi_meta_key(bucket),
2875 info,
2876 params.orig_info,
2877 params.exclusive,
2878 params.mtime,
2879 params.attrs,
b3b6e05e
TL
2880 y,
2881 dpp);
9f95a23c
TL
2882}
2883
2884int RGWBucketCtl::store_bucket_instance_info(const rgw_bucket& bucket,
2885 RGWBucketInfo& info,
2886 optional_yield y,
b3b6e05e 2887 const DoutPrefixProvider *dpp,
9f95a23c
TL
2888 const BucketInstance::PutParams& params)
2889{
2890 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& ctx) {
b3b6e05e 2891 return do_store_bucket_instance_info(ctx, bucket, info, y, dpp, params);
9f95a23c
TL
2892 });
2893}
2894
2895int RGWBucketCtl::remove_bucket_instance_info(const rgw_bucket& bucket,
2896 RGWBucketInfo& info,
2897 optional_yield y,
b3b6e05e 2898 const DoutPrefixProvider *dpp,
9f95a23c
TL
2899 const BucketInstance::RemoveParams& params)
2900{
2901 if (params.objv_tracker) {
2902 info.objv_tracker = *params.objv_tracker;
2903 }
2904
2905 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& ctx) {
2906 return svc.bucket->remove_bucket_instance_info(ctx,
2907 RGWSI_Bucket::get_bi_meta_key(bucket),
2908 info,
2909 &info.objv_tracker,
b3b6e05e
TL
2910 y,
2911 dpp);
9f95a23c
TL
2912 });
2913}
2914
2915int RGWBucketCtl::do_store_linked_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
2916 RGWBucketInfo& info,
2917 RGWBucketInfo *orig_info,
2918 bool exclusive, real_time mtime,
2919 obj_version *pep_objv,
2920 map<string, bufferlist> *pattrs,
2921 bool create_entry_point,
b3b6e05e 2922 optional_yield y, const DoutPrefixProvider *dpp)
9f95a23c
TL
2923{
2924 bool create_head = !info.has_instance_obj || create_entry_point;
2925
2926 int ret = svc.bucket->store_bucket_instance_info(ctx.bi,
2927 RGWSI_Bucket::get_bi_meta_key(info.bucket),
2928 info,
2929 orig_info,
2930 exclusive,
2931 mtime, pattrs,
b3b6e05e 2932 y, dpp);
9f95a23c
TL
2933 if (ret < 0) {
2934 return ret;
2935 }
2936
2937 if (!create_head)
2938 return 0; /* done! */
2939
2940 RGWBucketEntryPoint entry_point;
2941 entry_point.bucket = info.bucket;
2942 entry_point.owner = info.owner;
2943 entry_point.creation_time = info.creation_time;
2944 entry_point.linked = true;
2945 RGWObjVersionTracker ot;
2946 if (pep_objv && !pep_objv->tag.empty()) {
2947 ot.write_version = *pep_objv;
2948 } else {
2949 ot.generate_new_write_ver(cct);
2950 if (pep_objv) {
2951 *pep_objv = ot.write_version;
2952 }
2953 }
2954 ret = svc.bucket->store_bucket_entrypoint_info(ctx.ep,
2955 RGWSI_Bucket::get_entrypoint_meta_key(info.bucket),
2956 entry_point,
2957 exclusive,
2958 mtime,
2959 pattrs,
2960 &ot,
b3b6e05e
TL
2961 y,
2962 dpp);
9f95a23c
TL
2963 if (ret < 0)
2964 return ret;
2965
2966 return 0;
2967}
2968int RGWBucketCtl::convert_old_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
2969 const rgw_bucket& bucket,
b3b6e05e
TL
2970 optional_yield y,
2971 const DoutPrefixProvider *dpp)
9f95a23c
TL
2972{
2973 RGWBucketEntryPoint entry_point;
2974 real_time ep_mtime;
2975 RGWObjVersionTracker ot;
2976 map<string, bufferlist> attrs;
2977 RGWBucketInfo info;
2978 auto cct = svc.bucket->ctx();
2979
b3b6e05e 2980 ldpp_dout(dpp, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket << dendl;
9f95a23c
TL
2981
2982 int ret = svc.bucket->read_bucket_entrypoint_info(ctx.ep,
2983 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
b3b6e05e 2984 &entry_point, &ot, &ep_mtime, &attrs, y, dpp);
9f95a23c 2985 if (ret < 0) {
b3b6e05e 2986 ldpp_dout(dpp, 0) << "ERROR: get_bucket_entrypoint_info() returned " << ret << " bucket=" << bucket << dendl;
9f95a23c
TL
2987 return ret;
2988 }
2989
2990 if (!entry_point.has_bucket_info) {
2991 /* already converted! */
7c673cae
FG
2992 return 0;
2993 }
2994
9f95a23c
TL
2995 info = entry_point.old_bucket_info;
2996
2997 ot.generate_new_write_ver(cct);
2998
b3b6e05e 2999 ret = do_store_linked_bucket_info(ctx, info, nullptr, false, ep_mtime, &ot.write_version, &attrs, true, y, dpp);
9f95a23c 3000 if (ret < 0) {
b3b6e05e 3001 ldpp_dout(dpp, 0) << "ERROR: failed to put_linked_bucket_info(): " << ret << dendl;
9f95a23c 3002 return ret;
7c673cae
FG
3003 }
3004
9f95a23c
TL
3005 return 0;
3006}
3007
3008int RGWBucketCtl::set_bucket_instance_attrs(RGWBucketInfo& bucket_info,
3009 map<string, bufferlist>& attrs,
3010 RGWObjVersionTracker *objv_tracker,
b3b6e05e
TL
3011 optional_yield y,
3012 const DoutPrefixProvider *dpp)
9f95a23c
TL
3013{
3014 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
3015 rgw_bucket& bucket = bucket_info.bucket;
3016
3017 if (!bucket_info.has_instance_obj) {
3018 /* an old bucket object, need to convert it */
b3b6e05e 3019 int ret = convert_old_bucket_info(ctx, bucket, y, dpp);
9f95a23c 3020 if (ret < 0) {
b3b6e05e 3021 ldpp_dout(dpp, 0) << "ERROR: failed converting old bucket info: " << ret << dendl;
9f95a23c
TL
3022 return ret;
3023 }
3024 }
3025
3026 return do_store_bucket_instance_info(ctx.bi,
3027 bucket,
3028 bucket_info,
3029 y,
b3b6e05e 3030 dpp,
9f95a23c
TL
3031 BucketInstance::PutParams().set_attrs(&attrs)
3032 .set_objv_tracker(objv_tracker)
3033 .set_orig_info(&bucket_info));
3034 });
3035}
3036
3037
3038int RGWBucketCtl::link_bucket(const rgw_user& user_id,
3039 const rgw_bucket& bucket,
3040 ceph::real_time creation_time,
3041 optional_yield y,
b3b6e05e 3042 const DoutPrefixProvider *dpp,
9f95a23c
TL
3043 bool update_entrypoint,
3044 rgw_ep_info *pinfo)
3045{
3046 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
f67539c2 3047 return do_link_bucket(ctx, user_id, bucket, creation_time,
b3b6e05e 3048 update_entrypoint, pinfo, y, dpp);
9f95a23c
TL
3049 });
3050}
3051
3052int RGWBucketCtl::do_link_bucket(RGWSI_Bucket_EP_Ctx& ctx,
3053 const rgw_user& user_id,
3054 const rgw_bucket& bucket,
3055 ceph::real_time creation_time,
9f95a23c 3056 bool update_entrypoint,
f67539c2 3057 rgw_ep_info *pinfo,
b3b6e05e
TL
3058 optional_yield y,
3059 const DoutPrefixProvider *dpp)
9f95a23c
TL
3060{
3061 int ret;
3062
3063 RGWBucketEntryPoint ep;
3064 RGWObjVersionTracker ot;
3065 RGWObjVersionTracker& rot = (pinfo) ? pinfo->ep_objv : ot;
3066 map<string, bufferlist> attrs, *pattrs = nullptr;
3067 string meta_key;
3068
3069 if (update_entrypoint) {
3070 meta_key = RGWSI_Bucket::get_entrypoint_meta_key(bucket);
3071 if (pinfo) {
3072 ep = pinfo->ep;
3073 pattrs = &pinfo->attrs;
3074 } else {
3075 ret = svc.bucket->read_bucket_entrypoint_info(ctx,
3076 meta_key,
3077 &ep, &rot,
3078 nullptr, &attrs,
b3b6e05e 3079 y, dpp);
9f95a23c 3080 if (ret < 0 && ret != -ENOENT) {
b3b6e05e 3081 ldpp_dout(dpp, 0) << "ERROR: store->get_bucket_entrypoint_info() returned: "
9f95a23c
TL
3082 << cpp_strerror(-ret) << dendl;
3083 }
3084 pattrs = &attrs;
3085 }
181888fb
FG
3086 }
3087
b3b6e05e 3088 ret = ctl.user->add_bucket(dpp, user_id, bucket, creation_time, y);
9f95a23c 3089 if (ret < 0) {
b3b6e05e 3090 ldpp_dout(dpp, 0) << "ERROR: error adding bucket to user directory:"
9f95a23c
TL
3091 << " user=" << user_id
3092 << " bucket=" << bucket
3093 << " err=" << cpp_strerror(-ret)
3094 << dendl;
3095 goto done_err;
7c673cae 3096 }
7c673cae 3097
9f95a23c
TL
3098 if (!update_entrypoint)
3099 return 0;
3100
3101 ep.linked = true;
3102 ep.owner = user_id;
3103 ep.bucket = bucket;
3104 ret = svc.bucket->store_bucket_entrypoint_info(
b3b6e05e 3105 ctx, meta_key, ep, false, real_time(), pattrs, &rot, y, dpp);
9f95a23c
TL
3106 if (ret < 0)
3107 goto done_err;
3108
3109 return 0;
3110
3111done_err:
b3b6e05e 3112 int r = do_unlink_bucket(ctx, user_id, bucket, true, y, dpp);
9f95a23c 3113 if (r < 0) {
b3b6e05e 3114 ldpp_dout(dpp, 0) << "ERROR: failed unlinking bucket on error cleanup: "
9f95a23c
TL
3115 << cpp_strerror(-r) << dendl;
3116 }
3117 return ret;
3118}
3119
b3b6e05e 3120int RGWBucketCtl::unlink_bucket(const rgw_user& user_id, const rgw_bucket& bucket, optional_yield y, const DoutPrefixProvider *dpp, bool update_entrypoint)
9f95a23c
TL
3121{
3122 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
b3b6e05e 3123 return do_unlink_bucket(ctx, user_id, bucket, update_entrypoint, y, dpp);
9f95a23c
TL
3124 });
3125}
3126
3127int RGWBucketCtl::do_unlink_bucket(RGWSI_Bucket_EP_Ctx& ctx,
3128 const rgw_user& user_id,
3129 const rgw_bucket& bucket,
f67539c2 3130 bool update_entrypoint,
b3b6e05e
TL
3131 optional_yield y,
3132 const DoutPrefixProvider *dpp)
9f95a23c 3133{
b3b6e05e 3134 int ret = ctl.user->remove_bucket(dpp, user_id, bucket, y);
9f95a23c 3135 if (ret < 0) {
b3b6e05e 3136 ldpp_dout(dpp, 0) << "ERROR: error removing bucket from directory: "
9f95a23c
TL
3137 << cpp_strerror(-ret)<< dendl;
3138 }
3139
3140 if (!update_entrypoint)
3141 return 0;
3142
3143 RGWBucketEntryPoint ep;
3144 RGWObjVersionTracker ot;
3145 map<string, bufferlist> attrs;
3146 string meta_key = RGWSI_Bucket::get_entrypoint_meta_key(bucket);
b3b6e05e 3147 ret = svc.bucket->read_bucket_entrypoint_info(ctx, meta_key, &ep, &ot, nullptr, &attrs, y, dpp);
9f95a23c
TL
3148 if (ret == -ENOENT)
3149 return 0;
3150 if (ret < 0)
3151 return ret;
11fdf7f2 3152
9f95a23c 3153 if (!ep.linked)
11fdf7f2 3154 return 0;
9f95a23c
TL
3155
3156 if (ep.owner != user_id) {
b3b6e05e 3157 ldpp_dout(dpp, 0) << "bucket entry point user mismatch, can't unlink bucket: " << ep.owner << " != " << user_id << dendl;
9f95a23c 3158 return -EINVAL;
11fdf7f2 3159 }
11fdf7f2 3160
9f95a23c 3161 ep.linked = false;
b3b6e05e 3162 return svc.bucket->store_bucket_entrypoint_info(ctx, meta_key, ep, false, real_time(), &attrs, &ot, y, dpp);
9f95a23c
TL
3163}
3164
3165int RGWBucketCtl::set_acl(ACLOwner& owner, rgw_bucket& bucket,
3166 RGWBucketInfo& bucket_info, bufferlist& bl,
b3b6e05e
TL
3167 optional_yield y,
3168 const DoutPrefixProvider *dpp)
9f95a23c
TL
3169{
3170 // set owner and acl
3171 bucket_info.owner = owner.get_id();
3172 std::map<std::string, bufferlist> attrs{{RGW_ATTR_ACL, bl}};
3173
b3b6e05e 3174 int r = store_bucket_instance_info(bucket, bucket_info, y, dpp,
9f95a23c
TL
3175 BucketInstance::PutParams().set_attrs(&attrs));
3176 if (r < 0) {
3177 cerr << "ERROR: failed to set bucket owner: " << cpp_strerror(-r) << std::endl;
3178 return r;
3179 }
3180
3181 return 0;
3182}
3183
3184// TODO: remove RGWRados dependency for bucket listing
3185int RGWBucketCtl::chown(rgw::sal::RGWRadosStore *store, RGWBucketInfo& bucket_info,
3186 const rgw_user& user_id, const std::string& display_name,
b3b6e05e 3187 const std::string& marker, optional_yield y, const DoutPrefixProvider *dpp)
9f95a23c
TL
3188{
3189 RGWObjectCtx obj_ctx(store);
3190 std::vector<rgw_bucket_dir_entry> objs;
3191 map<string, bool> common_prefixes;
3192
3193 RGWRados::Bucket target(store->getRados(), bucket_info);
3194 RGWRados::Bucket::List list_op(&target);
3195
3196 list_op.params.list_versions = true;
3197 list_op.params.allow_unordered = true;
3198 list_op.params.marker = marker;
3199
3200 bool is_truncated = false;
3201 int count = 0;
3202 int max_entries = 1000;
3203
3204 //Loop through objects and update object acls to point to bucket owner
3205
3206 do {
3207 objs.clear();
b3b6e05e 3208 int ret = list_op.list_objects(dpp, max_entries, &objs, &common_prefixes, &is_truncated, y);
9f95a23c 3209 if (ret < 0) {
b3b6e05e 3210 ldpp_dout(dpp, 0) << "ERROR: list objects failed: " << cpp_strerror(-ret) << dendl;
9f95a23c
TL
3211 return ret;
3212 }
3213
3214 list_op.params.marker = list_op.get_next_marker();
3215 count += objs.size();
3216
3217 for (const auto& obj : objs) {
3218
3219 rgw_obj r_obj(bucket_info.bucket, obj.key);
3220 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, r_obj);
3221 RGWRados::Object::Read read_op(&op_target);
3222
3223 map<string, bufferlist> attrs;
3224 read_op.params.attrs = &attrs;
b3b6e05e 3225 ret = read_op.prepare(y, dpp);
9f95a23c 3226 if (ret < 0){
b3b6e05e 3227 ldpp_dout(dpp, 0) << "ERROR: failed to read object " << obj.key.name << cpp_strerror(-ret) << dendl;
9f95a23c
TL
3228 continue;
3229 }
3230 const auto& aiter = attrs.find(RGW_ATTR_ACL);
3231 if (aiter == attrs.end()) {
b3b6e05e 3232 ldpp_dout(dpp, 0) << "ERROR: no acls found for object " << obj.key.name << " .Continuing with next object." << dendl;
9f95a23c
TL
3233 continue;
3234 } else {
3235 bufferlist& bl = aiter->second;
3236 RGWAccessControlPolicy policy(store->ctx());
3237 ACLOwner owner;
3238 try {
3239 decode(policy, bl);
3240 owner = policy.get_owner();
3241 } catch (buffer::error& err) {
b3b6e05e 3242 ldpp_dout(dpp, 0) << "ERROR: decode policy failed" << err.what()
f67539c2 3243 << dendl;
9f95a23c
TL
3244 return -EIO;
3245 }
3246
3247 //Get the ACL from the policy
3248 RGWAccessControlList& acl = policy.get_acl();
3249
3250 //Remove grant that is set to old owner
3251 acl.remove_canon_user_grant(owner.get_id());
3252
3253 //Create a grant and add grant
3254 ACLGrant grant;
3255 grant.set_canon(user_id, display_name, RGW_PERM_FULL_CONTROL);
3256 acl.add_grant(&grant);
3257
3258 //Update the ACL owner to the new user
3259 owner.set_id(user_id);
3260 owner.set_name(display_name);
3261 policy.set_owner(owner);
3262
3263 bl.clear();
3264 encode(policy, bl);
3265
3266 obj_ctx.set_atomic(r_obj);
b3b6e05e 3267 ret = store->getRados()->set_attr(dpp, &obj_ctx, bucket_info, r_obj, RGW_ATTR_ACL, bl);
9f95a23c 3268 if (ret < 0) {
b3b6e05e 3269 ldpp_dout(dpp, 0) << "ERROR: modify attr failed " << cpp_strerror(-ret) << dendl;
9f95a23c
TL
3270 return ret;
3271 }
3272 }
3273 }
3274 cerr << count << " objects processed in " << bucket_info.bucket.name
3275 << ". Next marker " << list_op.params.marker.name << std::endl;
3276 } while(is_truncated);
3277 return 0;
11fdf7f2
TL
3278}
3279
9f95a23c
TL
3280int RGWBucketCtl::read_bucket_stats(const rgw_bucket& bucket,
3281 RGWBucketEnt *result,
b3b6e05e
TL
3282 optional_yield y,
3283 const DoutPrefixProvider *dpp)
9f95a23c
TL
3284{
3285 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
b3b6e05e 3286 return svc.bucket->read_bucket_stats(ctx, bucket, result, y, dpp);
9f95a23c
TL
3287 });
3288}
3289
3290int RGWBucketCtl::read_buckets_stats(map<string, RGWBucketEnt>& m,
b3b6e05e 3291 optional_yield y, const DoutPrefixProvider *dpp)
9f95a23c
TL
3292{
3293 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
b3b6e05e 3294 return svc.bucket->read_buckets_stats(ctx, m, y, dpp);
9f95a23c
TL
3295 });
3296}
3297
b3b6e05e
TL
3298int RGWBucketCtl::sync_user_stats(const DoutPrefixProvider *dpp,
3299 const rgw_user& user_id,
9f95a23c 3300 const RGWBucketInfo& bucket_info,
f67539c2 3301 optional_yield y,
9f95a23c
TL
3302 RGWBucketEnt* pent)
3303{
3304 RGWBucketEnt ent;
3305 if (!pent) {
3306 pent = &ent;
3307 }
b3b6e05e 3308 int r = svc.bi->read_stats(dpp, bucket_info, pent, null_yield);
9f95a23c 3309 if (r < 0) {
b3b6e05e 3310 ldpp_dout(dpp, 20) << __func__ << "(): failed to read bucket stats (r=" << r << ")" << dendl;
9f95a23c
TL
3311 return r;
3312 }
3313
b3b6e05e 3314 return ctl.user->flush_bucket_stats(dpp, user_id, *pent, y);
11fdf7f2
TL
3315}
3316
9f95a23c
TL
3317int RGWBucketCtl::get_sync_policy_handler(std::optional<rgw_zone_id> zone,
3318 std::optional<rgw_bucket> bucket,
3319 RGWBucketSyncPolicyHandlerRef *phandler,
b3b6e05e
TL
3320 optional_yield y,
3321 const DoutPrefixProvider *dpp)
9f95a23c
TL
3322{
3323 int r = call([&](RGWSI_Bucket_X_Ctx& ctx) {
b3b6e05e 3324 return svc.bucket_sync->get_policy_handler(ctx, zone, bucket, phandler, y, dpp);
9f95a23c
TL
3325 });
3326 if (r < 0) {
b3b6e05e 3327 ldpp_dout(dpp, 20) << __func__ << "(): failed to get policy handler for bucket=" << bucket << " (r=" << r << ")" << dendl;
9f95a23c
TL
3328 return r;
3329 }
3330 return 0;
11fdf7f2
TL
3331}
3332
9f95a23c 3333int RGWBucketCtl::bucket_exports_data(const rgw_bucket& bucket,
b3b6e05e
TL
3334 optional_yield y,
3335 const DoutPrefixProvider *dpp)
9f95a23c
TL
3336{
3337
3338 RGWBucketSyncPolicyHandlerRef handler;
3339
b3b6e05e 3340 int r = get_sync_policy_handler(std::nullopt, bucket, &handler, y, dpp);
9f95a23c
TL
3341 if (r < 0) {
3342 return r;
3343 }
3344
3345 return handler->bucket_exports_data();
11fdf7f2
TL
3346}
3347
9f95a23c 3348int RGWBucketCtl::bucket_imports_data(const rgw_bucket& bucket,
b3b6e05e 3349 optional_yield y, const DoutPrefixProvider *dpp)
7c673cae 3350{
9f95a23c
TL
3351
3352 RGWBucketSyncPolicyHandlerRef handler;
3353
b3b6e05e 3354 int r = get_sync_policy_handler(std::nullopt, bucket, &handler, y, dpp);
9f95a23c
TL
3355 if (r < 0) {
3356 return r;
11fdf7f2 3357 }
9f95a23c
TL
3358
3359 return handler->bucket_imports_data();
7c673cae 3360}
9f95a23c
TL
3361
3362RGWBucketMetadataHandlerBase *RGWBucketMetaHandlerAllocator::alloc()
3363{
3364 return new RGWBucketMetadataHandler();
3365}
3366
3367RGWBucketInstanceMetadataHandlerBase *RGWBucketInstanceMetaHandlerAllocator::alloc()
3368{
3369 return new RGWBucketInstanceMetadataHandler();
3370}
3371
3372RGWBucketMetadataHandlerBase *RGWArchiveBucketMetaHandlerAllocator::alloc()
3373{
3374 return new RGWArchiveBucketMetadataHandler();
3375}
3376
3377RGWBucketInstanceMetadataHandlerBase *RGWArchiveBucketInstanceMetaHandlerAllocator::alloc()
3378{
3379 return new RGWArchiveBucketInstanceMetadataHandler();
3380}
3381