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