]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_bucket.cc
bump version to 15.2.11-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
f6b5b4d7
TL
1403static int bucket_stats(rgw::sal::RGWRadosStore *store,
1404 const std::string& tenant_name,
1405 const std::string& bucket_name,
1406 Formatter *formatter)
7c673cae
FG
1407{
1408 RGWBucketInfo bucket_info;
1409 map<RGWObjCategory, RGWStorageStats> stats;
9f95a23c 1410 map<string, bufferlist> attrs;
7c673cae
FG
1411
1412 real_time mtime;
f6b5b4d7
TL
1413 int r = store->getRados()->get_bucket_info(store->svc(),
1414 tenant_name, bucket_name, bucket_info,
1415 &mtime, null_yield, &attrs);
1416 if (r < 0) {
7c673cae 1417 return r;
f6b5b4d7 1418 }
7c673cae
FG
1419
1420 rgw_bucket& bucket = bucket_info.bucket;
1421
1422 string bucket_ver, master_ver;
1423 string max_marker;
f6b5b4d7
TL
1424 int ret = store->getRados()->get_bucket_stats(bucket_info, RGW_NO_SHARD,
1425 &bucket_ver, &master_ver, stats,
1426 &max_marker);
7c673cae 1427 if (ret < 0) {
f91f0fd5 1428 cerr << "error getting bucket stats bucket=" << bucket.name << " ret=" << ret << std::endl;
7c673cae
FG
1429 return ret;
1430 }
1431
1432 utime_t ut(mtime);
9f95a23c 1433 utime_t ctime_ut(bucket_info.creation_time);
7c673cae
FG
1434
1435 formatter->open_object_section("stats");
1436 formatter->dump_string("bucket", bucket.name);
92f5a8d4 1437 formatter->dump_int("num_shards", bucket_info.num_shards);
11fdf7f2 1438 formatter->dump_string("tenant", bucket.tenant);
31f18b77 1439 formatter->dump_string("zonegroup", bucket_info.zonegroup);
11fdf7f2 1440 formatter->dump_string("placement_rule", bucket_info.placement_rule.to_str());
31f18b77 1441 ::encode_json("explicit_placement", bucket.explicit_placement, formatter);
7c673cae
FG
1442 formatter->dump_string("id", bucket.bucket_id);
1443 formatter->dump_string("marker", bucket.marker);
1444 formatter->dump_stream("index_type") << bucket_info.index_type;
1445 ::encode_json("owner", bucket_info.owner, formatter);
1446 formatter->dump_string("ver", bucket_ver);
1447 formatter->dump_string("master_ver", master_ver);
81eedcae 1448 ut.gmtime(formatter->dump_stream("mtime"));
9f95a23c 1449 ctime_ut.gmtime(formatter->dump_stream("creation_time"));
7c673cae
FG
1450 formatter->dump_string("max_marker", max_marker);
1451 dump_bucket_usage(stats, formatter);
1452 encode_json("bucket_quota", bucket_info.quota, formatter);
9f95a23c
TL
1453
1454 // bucket tags
1455 auto iter = attrs.find(RGW_ATTR_TAGS);
1456 if (iter != attrs.end()) {
1457 RGWObjTagSet_S3 tagset;
1458 bufferlist::const_iterator piter{&iter->second};
1459 try {
1460 tagset.decode(piter);
1461 tagset.dump(formatter);
1462 } catch (buffer::error& err) {
1463 cerr << "ERROR: caught buffer:error, couldn't decode TagSet" << std::endl;
1464 }
1465 }
1466
1467 // TODO: bucket CORS
1468 // TODO: bucket LC
7c673cae
FG
1469 formatter->close_section();
1470
1471 return 0;
1472}
1473
9f95a23c 1474int RGWBucketAdminOp::limit_check(rgw::sal::RGWRadosStore *store,
7c673cae
FG
1475 RGWBucketAdminOpState& op_state,
1476 const std::list<std::string>& user_ids,
1477 RGWFormatterFlusher& flusher,
1478 bool warnings_only)
1479{
1480 int ret = 0;
1481 const size_t max_entries =
1482 store->ctx()->_conf->rgw_list_buckets_max_chunk;
1483
1484 const size_t safe_max_objs_per_shard =
1485 store->ctx()->_conf->rgw_safe_max_objects_per_shard;
1486
1487 uint16_t shard_warn_pct =
1488 store->ctx()->_conf->rgw_shard_warning_threshold;
1489 if (shard_warn_pct > 100)
1490 shard_warn_pct = 90;
1491
1492 Formatter *formatter = flusher.get_formatter();
1493 flusher.start(0);
1494
1495 formatter->open_array_section("users");
1496
1497 for (const auto& user_id : user_ids) {
a8e16298 1498
7c673cae
FG
1499 formatter->open_object_section("user");
1500 formatter->dump_string("user_id", user_id);
7c673cae 1501 formatter->open_array_section("buckets");
a8e16298
TL
1502
1503 string marker;
9f95a23c 1504 rgw::sal::RGWBucketList buckets;
7c673cae 1505 do {
9f95a23c
TL
1506 rgw::sal::RGWRadosUser user(store, rgw_user(user_id));
1507
1508 ret = user.list_buckets(marker, string(), max_entries, false, buckets);
7c673cae 1509
7c673cae
FG
1510 if (ret < 0)
1511 return ret;
1512
9f95a23c 1513 map<string, rgw::sal::RGWBucket*>& m_buckets = buckets.get_buckets();
7c673cae
FG
1514
1515 for (const auto& iter : m_buckets) {
9f95a23c 1516 auto bucket = iter.second;
7c673cae
FG
1517 uint32_t num_shards = 1;
1518 uint64_t num_objects = 0;
1519
1520 /* need info for num_shards */
1521 RGWBucketInfo info;
7c673cae 1522
9f95a23c
TL
1523 marker = bucket->get_name(); /* Casey's location for marker update,
1524 * as we may now not reach the end of
1525 * the loop body */
7c673cae 1526
9f95a23c
TL
1527 ret = store->getRados()->get_bucket_info(store->svc(), bucket->get_tenant(),
1528 bucket->get_name(), info, nullptr,
1529 null_yield);
7c673cae
FG
1530 if (ret < 0)
1531 continue;
1532
1533 /* need stats for num_entries */
1534 string bucket_ver, master_ver;
1535 std::map<RGWObjCategory, RGWStorageStats> stats;
9f95a23c 1536 ret = store->getRados()->get_bucket_stats(info, RGW_NO_SHARD, &bucket_ver,
7c673cae
FG
1537 &master_ver, stats, nullptr);
1538
1539 if (ret < 0)
1540 continue;
1541
1542 for (const auto& s : stats) {
adb31ebb 1543 num_objects += s.second.num_objects;
7c673cae
FG
1544 }
1545
1546 num_shards = info.num_shards;
31f18b77
FG
1547 uint64_t objs_per_shard =
1548 (num_shards) ? num_objects/num_shards : num_objects;
7c673cae 1549 {
adb31ebb 1550 bool warn;
7c673cae 1551 stringstream ss;
adb31ebb
TL
1552 uint64_t fill_pct = objs_per_shard * 100 / safe_max_objs_per_shard;
1553 if (fill_pct > 100) {
1554 ss << "OVER " << fill_pct << "%";
1555 warn = true;
1556 } else if (fill_pct >= shard_warn_pct) {
1557 ss << "WARN " << fill_pct << "%";
1558 warn = true;
7c673cae 1559 } else {
adb31ebb
TL
1560 ss << "OK";
1561 warn = false;
7c673cae
FG
1562 }
1563
adb31ebb 1564 if (warn || !warnings_only) {
7c673cae 1565 formatter->open_object_section("bucket");
9f95a23c
TL
1566 formatter->dump_string("bucket", bucket->get_name());
1567 formatter->dump_string("tenant", bucket->get_tenant());
7c673cae
FG
1568 formatter->dump_int("num_objects", num_objects);
1569 formatter->dump_int("num_shards", num_shards);
1570 formatter->dump_int("objects_per_shard", objs_per_shard);
1571 formatter->dump_string("fill_status", ss.str());
1572 formatter->close_section();
1573 }
1574 }
1575 }
a8e16298 1576 formatter->flush(cout);
9f95a23c 1577 } while (buckets.is_truncated()); /* foreach: bucket */
7c673cae
FG
1578
1579 formatter->close_section();
1580 formatter->close_section();
1581 formatter->flush(cout);
1582
1583 } /* foreach: user_id */
1584
1585 formatter->close_section();
1586 formatter->flush(cout);
1587
1588 return ret;
1589} /* RGWBucketAdminOp::limit_check */
1590
f6b5b4d7
TL
1591int RGWBucketAdminOp::info(rgw::sal::RGWRadosStore *store,
1592 RGWBucketAdminOpState& op_state,
1593 RGWFormatterFlusher& flusher)
7c673cae 1594{
adb31ebb 1595 RGWBucket bucket;
11fdf7f2 1596 int ret = 0;
f6b5b4d7 1597 const std::string& bucket_name = op_state.get_bucket_name();
adb31ebb
TL
1598 if (!bucket_name.empty()) {
1599 ret = bucket.init(store, op_state, null_yield);
1600 if (-ENOENT == ret)
1601 return -ERR_NO_SUCH_BUCKET;
1602 else if (ret < 0)
1603 return ret;
1604 }
1605
7c673cae
FG
1606 Formatter *formatter = flusher.get_formatter();
1607 flusher.start(0);
1608
1609 CephContext *cct = store->ctx();
1610
1611 const size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk;
1612
f6b5b4d7
TL
1613 const bool show_stats = op_state.will_fetch_stats();
1614 const rgw_user& user_id = op_state.get_user_id();
7c673cae
FG
1615 if (op_state.is_user_op()) {
1616 formatter->open_array_section("buckets");
1617
9f95a23c
TL
1618 rgw::sal::RGWBucketList buckets;
1619 rgw::sal::RGWRadosUser user(store, op_state.get_user_id());
f6b5b4d7
TL
1620 std::string marker;
1621 const std::string empty_end_marker;
1622 constexpr bool no_need_stats = false; // set need_stats to false
7c673cae
FG
1623
1624 do {
f6b5b4d7
TL
1625 buckets.clear();
1626 ret = user.list_buckets(marker, empty_end_marker, max_entries,
1627 no_need_stats, buckets);
1628 if (ret < 0) {
7c673cae 1629 return ret;
f6b5b4d7 1630 }
7c673cae 1631
f6b5b4d7 1632 const std::string* marker_cursor = nullptr;
9f95a23c 1633 map<string, rgw::sal::RGWBucket*>& m = buckets.get_buckets();
7c673cae 1634
f6b5b4d7
TL
1635 for (const auto& i : m) {
1636 const std::string& obj_name = i.first;
11fdf7f2
TL
1637 if (!bucket_name.empty() && bucket_name != obj_name) {
1638 continue;
1639 }
1640
f6b5b4d7 1641 if (show_stats) {
7c673cae 1642 bucket_stats(store, user_id.tenant, obj_name, formatter);
f6b5b4d7 1643 } else {
7c673cae 1644 formatter->dump_string("bucket", obj_name);
f6b5b4d7 1645 }
7c673cae 1646
f6b5b4d7
TL
1647 marker_cursor = &obj_name;
1648 } // for loop
1649 if (marker_cursor) {
1650 marker = *marker_cursor;
7c673cae
FG
1651 }
1652
1653 flusher.flush();
f6b5b4d7 1654 } while (buckets.is_truncated());
7c673cae
FG
1655
1656 formatter->close_section();
1657 } else if (!bucket_name.empty()) {
11fdf7f2
TL
1658 ret = bucket_stats(store, user_id.tenant, bucket_name, formatter);
1659 if (ret < 0) {
1660 return ret;
1661 }
7c673cae 1662 } else {
11fdf7f2
TL
1663 void *handle = nullptr;
1664 bool truncated = true;
7c673cae
FG
1665
1666 formatter->open_array_section("buckets");
9f95a23c 1667 ret = store->ctl()->meta.mgr->list_keys_init("bucket", &handle);
11fdf7f2
TL
1668 while (ret == 0 && truncated) {
1669 std::list<std::string> buckets;
f6b5b4d7 1670 constexpr int max_keys = 1000;
9f95a23c 1671 ret = store->ctl()->meta.mgr->list_keys_next(handle, max_keys, buckets,
f6b5b4d7 1672 &truncated);
11fdf7f2 1673 for (auto& bucket_name : buckets) {
f6b5b4d7 1674 if (show_stats) {
11fdf7f2 1675 bucket_stats(store, user_id.tenant, bucket_name, formatter);
f6b5b4d7 1676 } else {
11fdf7f2 1677 formatter->dump_string("bucket", bucket_name);
f6b5b4d7 1678 }
7c673cae
FG
1679 }
1680 }
e306af50 1681 store->ctl()->meta.mgr->list_keys_complete(handle);
7c673cae
FG
1682
1683 formatter->close_section();
1684 }
1685
1686 flusher.flush();
1687
1688 return 0;
1689}
1690
9f95a23c 1691int RGWBucketAdminOp::set_quota(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state)
94b18763
FG
1692{
1693 RGWBucket bucket;
1694
9f95a23c 1695 int ret = bucket.init(store, op_state, null_yield);
94b18763
FG
1696 if (ret < 0)
1697 return ret;
1698 return bucket.set_quota(op_state);
1699}
7c673cae 1700
9f95a23c 1701static int purge_bucket_instance(rgw::sal::RGWRadosStore *store, const RGWBucketInfo& bucket_info)
f64942e4
AA
1702{
1703 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
1704 for (int i = 0; i < max_shards; i++) {
9f95a23c 1705 RGWRados::BucketShard bs(store->getRados());
f64942e4
AA
1706 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
1707 int ret = bs.init(bucket_info.bucket, shard_id, nullptr);
1708 if (ret < 0) {
1709 cerr << "ERROR: bs.init(bucket=" << bucket_info.bucket << ", shard=" << shard_id
1710 << "): " << cpp_strerror(-ret) << std::endl;
1711 return ret;
1712 }
9f95a23c 1713 ret = store->getRados()->bi_remove(bs);
f64942e4
AA
1714 if (ret < 0) {
1715 cerr << "ERROR: failed to remove bucket index object: "
1716 << cpp_strerror(-ret) << std::endl;
1717 return ret;
1718 }
1719 }
1720 return 0;
1721}
1722
11fdf7f2 1723inline auto split_tenant(const std::string& bucket_name){
f64942e4
AA
1724 auto p = bucket_name.find('/');
1725 if(p != std::string::npos) {
1726 return std::make_pair(bucket_name.substr(0,p), bucket_name.substr(p+1));
1727 }
1728 return std::make_pair(std::string(), bucket_name);
1729}
1730
1731using bucket_instance_ls = std::vector<RGWBucketInfo>;
9f95a23c 1732void get_stale_instances(rgw::sal::RGWRadosStore *store, const std::string& bucket_name,
f64942e4
AA
1733 const vector<std::string>& lst,
1734 bucket_instance_ls& stale_instances)
1735{
1736
9f95a23c 1737 auto obj_ctx = store->svc()->sysobj->init_obj_ctx();
f64942e4
AA
1738
1739 bucket_instance_ls other_instances;
1740// first iterate over the entries, and pick up the done buckets; these
1741// are guaranteed to be stale
1742 for (const auto& bucket_instance : lst){
1743 RGWBucketInfo binfo;
9f95a23c
TL
1744 int r = store->getRados()->get_bucket_instance_info(obj_ctx, bucket_instance,
1745 binfo, nullptr,nullptr, null_yield);
f64942e4
AA
1746 if (r < 0){
1747 // this can only happen if someone deletes us right when we're processing
1748 lderr(store->ctx()) << "Bucket instance is invalid: " << bucket_instance
1749 << cpp_strerror(-r) << dendl;
1750 continue;
1751 }
9f95a23c 1752 if (binfo.reshard_status == cls_rgw_reshard_status::DONE)
f64942e4
AA
1753 stale_instances.emplace_back(std::move(binfo));
1754 else {
1755 other_instances.emplace_back(std::move(binfo));
1756 }
1757 }
1758
1759 // Read the cur bucket info, if the bucket doesn't exist we can simply return
1760 // all the instances
11fdf7f2 1761 auto [tenant, bucket] = split_tenant(bucket_name);
f64942e4 1762 RGWBucketInfo cur_bucket_info;
9f95a23c 1763 int r = store->getRados()->get_bucket_info(store->svc(), tenant, bucket, cur_bucket_info, nullptr, null_yield);
f64942e4
AA
1764 if (r < 0) {
1765 if (r == -ENOENT) {
1766 // bucket doesn't exist, everything is stale then
1767 stale_instances.insert(std::end(stale_instances),
1768 std::make_move_iterator(other_instances.begin()),
1769 std::make_move_iterator(other_instances.end()));
1770 } else {
1771 // all bets are off if we can't read the bucket, just return the sureshot stale instances
1772 lderr(store->ctx()) << "error: reading bucket info for bucket: "
1773 << bucket << cpp_strerror(-r) << dendl;
1774 }
1775 return;
1776 }
1777
1778 // Don't process further in this round if bucket is resharding
9f95a23c 1779 if (cur_bucket_info.reshard_status == cls_rgw_reshard_status::IN_PROGRESS)
f64942e4
AA
1780 return;
1781
1782 other_instances.erase(std::remove_if(other_instances.begin(), other_instances.end(),
1783 [&cur_bucket_info](const RGWBucketInfo& b){
1784 return (b.bucket.bucket_id == cur_bucket_info.bucket.bucket_id ||
1785 b.bucket.bucket_id == cur_bucket_info.new_bucket_instance_id);
1786 }),
1787 other_instances.end());
1788
1789 // check if there are still instances left
1790 if (other_instances.empty()) {
1791 return;
1792 }
1793
1794 // Now we have a bucket with instances where the reshard status is none, this
1795 // usually happens when the reshard process couldn't complete, lockdown the
1796 // bucket and walk through these instances to make sure no one else interferes
1797 // with these
1798 {
1799 RGWBucketReshardLock reshard_lock(store, cur_bucket_info, true);
1800 r = reshard_lock.lock();
1801 if (r < 0) {
1802 // most likely bucket is under reshard, return the sureshot stale instances
1803 ldout(store->ctx(), 5) << __func__
1804 << "failed to take reshard lock; reshard underway likey" << dendl;
1805 return;
1806 }
1807 auto sg = make_scope_guard([&reshard_lock](){ reshard_lock.unlock();} );
1808 // this should be fast enough that we may not need to renew locks and check
1809 // exit status?, should we read the values of the instances again?
1810 stale_instances.insert(std::end(stale_instances),
1811 std::make_move_iterator(other_instances.begin()),
1812 std::make_move_iterator(other_instances.end()));
1813 }
1814
1815 return;
1816}
1817
9f95a23c 1818static int process_stale_instances(rgw::sal::RGWRadosStore *store, RGWBucketAdminOpState& op_state,
f64942e4
AA
1819 RGWFormatterFlusher& flusher,
1820 std::function<void(const bucket_instance_ls&,
1821 Formatter *,
9f95a23c 1822 rgw::sal::RGWRadosStore*)> process_f)
f64942e4
AA
1823{
1824 std::string marker;
1825 void *handle;
1826 Formatter *formatter = flusher.get_formatter();
1827 static constexpr auto default_max_keys = 1000;
1828
9f95a23c 1829 int ret = store->ctl()->meta.mgr->list_keys_init("bucket.instance", marker, &handle);
f64942e4
AA
1830 if (ret < 0) {
1831 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
1832 return ret;
1833 }
1834
1835 bool truncated;
1836
1837 formatter->open_array_section("keys");
e306af50
TL
1838 auto g = make_scope_guard([&store, &handle, &formatter]() {
1839 store->ctl()->meta.mgr->list_keys_complete(handle);
1840 formatter->close_section(); // keys
1841 formatter->flush(cout);
1842 });
f64942e4
AA
1843
1844 do {
1845 list<std::string> keys;
1846
9f95a23c 1847 ret = store->ctl()->meta.mgr->list_keys_next(handle, default_max_keys, keys, &truncated);
f64942e4
AA
1848 if (ret < 0 && ret != -ENOENT) {
1849 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
1850 return ret;
1851 } if (ret != -ENOENT) {
1852 // partition the list of buckets by buckets as the listing is un sorted,
1853 // since it would minimize the reads to bucket_info
1854 std::unordered_map<std::string, std::vector<std::string>> bucket_instance_map;
1855 for (auto &key: keys) {
1856 auto pos = key.find(':');
1857 if(pos != std::string::npos)
1858 bucket_instance_map[key.substr(0,pos)].emplace_back(std::move(key));
1859 }
1860 for (const auto& kv: bucket_instance_map) {
1861 bucket_instance_ls stale_lst;
1862 get_stale_instances(store, kv.first, kv.second, stale_lst);
1863 process_f(stale_lst, formatter, store);
1864 }
1865 }
1866 } while (truncated);
1867
f64942e4
AA
1868 return 0;
1869}
1870
9f95a23c 1871int RGWBucketAdminOp::list_stale_instances(rgw::sal::RGWRadosStore *store,
f64942e4
AA
1872 RGWBucketAdminOpState& op_state,
1873 RGWFormatterFlusher& flusher)
1874{
1875 auto process_f = [](const bucket_instance_ls& lst,
1876 Formatter *formatter,
9f95a23c 1877 rgw::sal::RGWRadosStore*){
f64942e4
AA
1878 for (const auto& binfo: lst)
1879 formatter->dump_string("key", binfo.bucket.get_key());
1880 };
1881 return process_stale_instances(store, op_state, flusher, process_f);
1882}
1883
1884
9f95a23c 1885int RGWBucketAdminOp::clear_stale_instances(rgw::sal::RGWRadosStore *store,
f64942e4
AA
1886 RGWBucketAdminOpState& op_state,
1887 RGWFormatterFlusher& flusher)
1888{
1889 auto process_f = [](const bucket_instance_ls& lst,
1890 Formatter *formatter,
9f95a23c 1891 rgw::sal::RGWRadosStore *store){
f64942e4
AA
1892 for (const auto &binfo: lst) {
1893 int ret = purge_bucket_instance(store, binfo);
1894 if (ret == 0){
1895 auto md_key = "bucket.instance:" + binfo.bucket.get_key();
9f95a23c 1896 ret = store->ctl()->meta.mgr->remove(md_key, null_yield);
f64942e4
AA
1897 }
1898 formatter->open_object_section("delete_status");
1899 formatter->dump_string("bucket_instance", binfo.bucket.get_key());
1900 formatter->dump_int("status", -ret);
1901 formatter->close_section();
1902 }
1903 };
1904
1905 return process_stale_instances(store, op_state, flusher, process_f);
1906}
1907
9f95a23c 1908static int fix_single_bucket_lc(rgw::sal::RGWRadosStore *store,
11fdf7f2
TL
1909 const std::string& tenant_name,
1910 const std::string& bucket_name)
1911{
11fdf7f2
TL
1912 RGWBucketInfo bucket_info;
1913 map <std::string, bufferlist> bucket_attrs;
9f95a23c
TL
1914 int ret = store->getRados()->get_bucket_info(store->svc(), tenant_name, bucket_name,
1915 bucket_info, nullptr, null_yield, &bucket_attrs);
11fdf7f2
TL
1916 if (ret < 0) {
1917 // TODO: Should we handle the case where the bucket could've been removed between
1918 // listing and fetching?
1919 return ret;
1920 }
1921
1922 return rgw::lc::fix_lc_shard_entry(store, bucket_info, bucket_attrs);
1923}
1924
1925static void format_lc_status(Formatter* formatter,
1926 const std::string& tenant_name,
1927 const std::string& bucket_name,
1928 int status)
1929{
1930 formatter->open_object_section("bucket_entry");
1931 std::string entry = tenant_name.empty() ? bucket_name : tenant_name + "/" + bucket_name;
1932 formatter->dump_string("bucket", entry);
1933 formatter->dump_int("status", status);
1934 formatter->close_section(); // bucket_entry
1935}
1936
9f95a23c
TL
1937static void process_single_lc_entry(rgw::sal::RGWRadosStore *store,
1938 Formatter *formatter,
11fdf7f2
TL
1939 const std::string& tenant_name,
1940 const std::string& bucket_name)
1941{
1942 int ret = fix_single_bucket_lc(store, tenant_name, bucket_name);
1943 format_lc_status(formatter, tenant_name, bucket_name, -ret);
1944}
1945
9f95a23c 1946int RGWBucketAdminOp::fix_lc_shards(rgw::sal::RGWRadosStore *store,
11fdf7f2
TL
1947 RGWBucketAdminOpState& op_state,
1948 RGWFormatterFlusher& flusher)
1949{
1950 std::string marker;
1951 void *handle;
1952 Formatter *formatter = flusher.get_formatter();
1953 static constexpr auto default_max_keys = 1000;
1954
1955 bool truncated;
1956 if (const std::string& bucket_name = op_state.get_bucket_name();
1957 ! bucket_name.empty()) {
1958 const rgw_user user_id = op_state.get_user_id();
1959 process_single_lc_entry(store, formatter, user_id.tenant, bucket_name);
1960 formatter->flush(cout);
1961 } else {
9f95a23c 1962 int ret = store->ctl()->meta.mgr->list_keys_init("bucket", marker, &handle);
11fdf7f2
TL
1963 if (ret < 0) {
1964 std::cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
1965 return ret;
1966 }
1967
1968 {
1969 formatter->open_array_section("lc_fix_status");
1970 auto sg = make_scope_guard([&store, &handle, &formatter](){
9f95a23c 1971 store->ctl()->meta.mgr->list_keys_complete(handle);
11fdf7f2
TL
1972 formatter->close_section(); // lc_fix_status
1973 formatter->flush(cout);
1974 });
1975 do {
1976 list<std::string> keys;
9f95a23c 1977 ret = store->ctl()->meta.mgr->list_keys_next(handle, default_max_keys, keys, &truncated);
11fdf7f2
TL
1978 if (ret < 0 && ret != -ENOENT) {
1979 std::cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
1980 return ret;
1981 } if (ret != -ENOENT) {
1982 for (const auto &key:keys) {
1983 auto [tenant_name, bucket_name] = split_tenant(key);
1984 process_single_lc_entry(store, formatter, tenant_name, bucket_name);
1985 }
1986 }
1987 formatter->flush(cout); // regularly flush every 1k entries
1988 } while (truncated);
1989 }
1990
1991 }
1992 return 0;
1993
1994}
1995
9f95a23c
TL
1996static bool has_object_expired(rgw::sal::RGWRadosStore *store,
1997 const RGWBucketInfo& bucket_info,
81eedcae
TL
1998 const rgw_obj_key& key, utime_t& delete_at)
1999{
2000 rgw_obj obj(bucket_info.bucket, key);
2001 bufferlist delete_at_bl;
2002
9f95a23c 2003 int ret = rgw_object_get_attr(store, bucket_info, obj, RGW_ATTR_DELETE_AT, delete_at_bl, null_yield);
81eedcae
TL
2004 if (ret < 0) {
2005 return false; // no delete at attr, proceed
2006 }
2007
2008 ret = decode_bl(delete_at_bl, delete_at);
2009 if (ret < 0) {
2010 return false; // failed to parse
2011 }
2012
2013 if (delete_at <= ceph_clock_now() && !delete_at.is_zero()) {
2014 return true;
2015 }
2016
2017 return false;
2018}
2019
9f95a23c
TL
2020static int fix_bucket_obj_expiry(rgw::sal::RGWRadosStore *store,
2021 const RGWBucketInfo& bucket_info,
81eedcae
TL
2022 RGWFormatterFlusher& flusher, bool dry_run)
2023{
2024 if (bucket_info.bucket.bucket_id == bucket_info.bucket.marker) {
2025 lderr(store->ctx()) << "Not a resharded bucket skipping" << dendl;
2026 return 0; // not a resharded bucket, move along
2027 }
2028
2029 Formatter *formatter = flusher.get_formatter();
2030 formatter->open_array_section("expired_deletion_status");
2031 auto sg = make_scope_guard([&formatter] {
2032 formatter->close_section();
2033 formatter->flush(std::cout);
2034 });
2035
9f95a23c 2036 RGWRados::Bucket target(store->getRados(), bucket_info);
81eedcae
TL
2037 RGWRados::Bucket::List list_op(&target);
2038
2039 list_op.params.list_versions = bucket_info.versioned();
2040 list_op.params.allow_unordered = true;
2041
81eedcae
TL
2042 bool is_truncated {false};
2043 do {
2044 std::vector<rgw_bucket_dir_entry> objs;
2045
9f95a23c
TL
2046 int ret = list_op.list_objects(listing_max_entries, &objs, nullptr,
2047 &is_truncated, null_yield);
81eedcae
TL
2048 if (ret < 0) {
2049 lderr(store->ctx()) << "ERROR failed to list objects in the bucket" << dendl;
2050 return ret;
2051 }
2052 for (const auto& obj : objs) {
2053 rgw_obj_key key(obj.key);
2054 utime_t delete_at;
2055 if (has_object_expired(store, bucket_info, key, delete_at)) {
2056 formatter->open_object_section("object_status");
2057 formatter->dump_string("object", key.name);
2058 formatter->dump_stream("delete_at") << delete_at;
2059
2060 if (!dry_run) {
2061 ret = rgw_remove_object(store, bucket_info, bucket_info.bucket, key);
2062 formatter->dump_int("status", ret);
2063 }
2064
2065 formatter->close_section(); // object_status
2066 }
2067 }
2068 formatter->flush(cout); // regularly flush every 1k entries
2069 } while (is_truncated);
2070
2071 return 0;
2072}
2073
9f95a23c
TL
2074int RGWBucketAdminOp::fix_obj_expiry(rgw::sal::RGWRadosStore *store,
2075 RGWBucketAdminOpState& op_state,
81eedcae
TL
2076 RGWFormatterFlusher& flusher, bool dry_run)
2077{
2078 RGWBucket admin_bucket;
9f95a23c 2079 int ret = admin_bucket.init(store, op_state, null_yield);
81eedcae
TL
2080 if (ret < 0) {
2081 lderr(store->ctx()) << "failed to initialize bucket" << dendl;
2082 return ret;
2083 }
2084
2085 return fix_bucket_obj_expiry(store, admin_bucket.get_bucket_info(), flusher, dry_run);
2086}
2087
7c673cae
FG
2088void rgw_data_change::dump(Formatter *f) const
2089{
2090 string type;
2091 switch (entity_type) {
2092 case ENTITY_TYPE_BUCKET:
2093 type = "bucket";
2094 break;
2095 default:
2096 type = "unknown";
2097 }
2098 encode_json("entity_type", type, f);
2099 encode_json("key", key, f);
2100 utime_t ut(timestamp);
2101 encode_json("timestamp", ut, f);
2102}
2103
2104void rgw_data_change::decode_json(JSONObj *obj) {
2105 string s;
2106 JSONDecoder::decode_json("entity_type", s, obj);
2107 if (s == "bucket") {
2108 entity_type = ENTITY_TYPE_BUCKET;
2109 } else {
2110 entity_type = ENTITY_TYPE_UNKNOWN;
2111 }
2112 JSONDecoder::decode_json("key", key, obj);
2113 utime_t ut;
2114 JSONDecoder::decode_json("timestamp", ut, obj);
2115 timestamp = ut.to_real_time();
2116}
2117
2118void rgw_data_change_log_entry::dump(Formatter *f) const
2119{
2120 encode_json("log_id", log_id, f);
2121 utime_t ut(log_timestamp);
2122 encode_json("log_timestamp", ut, f);
2123 encode_json("entry", entry, f);
2124}
2125
2126void rgw_data_change_log_entry::decode_json(JSONObj *obj) {
2127 JSONDecoder::decode_json("log_id", log_id, obj);
2128 utime_t ut;
2129 JSONDecoder::decode_json("log_timestamp", ut, obj);
2130 log_timestamp = ut.to_real_time();
2131 JSONDecoder::decode_json("entry", entry, obj);
2132}
2133
9f95a23c
TL
2134
2135RGWDataChangesLog::RGWDataChangesLog(RGWSI_Zone *zone_svc, RGWSI_Cls *cls_svc)
2136 : cct(zone_svc->ctx()), changes(cct->_conf->rgw_data_log_changes_size)
2137{
2138 svc.zone = zone_svc;
2139 svc.cls = cls_svc;
2140
2141 num_shards = cct->_conf->rgw_data_log_num_shards;
2142
2143 oids = new string[num_shards];
2144
2145 string prefix = cct->_conf->rgw_data_log_obj_prefix;
2146
2147 if (prefix.empty()) {
2148 prefix = "data_log";
2149 }
2150
2151 for (int i = 0; i < num_shards; i++) {
2152 char buf[16];
2153 snprintf(buf, sizeof(buf), "%s.%d", prefix.c_str(), i);
2154 oids[i] = buf;
2155 }
2156
2157 renew_thread = new ChangesRenewThread(cct, this);
2158 renew_thread->create("rgw_dt_lg_renew");
2159}
2160
7c673cae
FG
2161int RGWDataChangesLog::choose_oid(const rgw_bucket_shard& bs) {
2162 const string& name = bs.bucket.name;
2163 int shard_shift = (bs.shard_id > 0 ? bs.shard_id : 0);
2164 uint32_t r = (ceph_str_hash_linux(name.c_str(), name.size()) + shard_shift) % num_shards;
2165
2166 return (int)r;
2167}
2168
2169int RGWDataChangesLog::renew_entries()
2170{
9f95a23c 2171 if (!svc.zone->need_to_log_data())
7c673cae
FG
2172 return 0;
2173
2174 /* we can't keep the bucket name as part of the cls_log_entry, and we need
2175 * it later, so we keep two lists under the map */
2176 map<int, pair<list<rgw_bucket_shard>, list<cls_log_entry> > > m;
2177
9f95a23c 2178 lock.lock();
7c673cae
FG
2179 map<rgw_bucket_shard, bool> entries;
2180 entries.swap(cur_cycle);
9f95a23c 2181 lock.unlock();
7c673cae
FG
2182
2183 map<rgw_bucket_shard, bool>::iterator iter;
2184 string section;
2185 real_time ut = real_clock::now();
2186 for (iter = entries.begin(); iter != entries.end(); ++iter) {
2187 const rgw_bucket_shard& bs = iter->first;
2188
2189 int index = choose_oid(bs);
2190
2191 cls_log_entry entry;
2192
2193 rgw_data_change change;
2194 bufferlist bl;
2195 change.entity_type = ENTITY_TYPE_BUCKET;
2196 change.key = bs.get_key();
2197 change.timestamp = ut;
11fdf7f2 2198 encode(change, bl);
7c673cae 2199
9f95a23c 2200 svc.cls->timelog.prepare_entry(entry, ut, section, change.key, bl);
7c673cae
FG
2201
2202 m[index].first.push_back(bs);
2203 m[index].second.emplace_back(std::move(entry));
2204 }
2205
2206 map<int, pair<list<rgw_bucket_shard>, list<cls_log_entry> > >::iterator miter;
2207 for (miter = m.begin(); miter != m.end(); ++miter) {
2208 list<cls_log_entry>& entries = miter->second.second;
2209
2210 real_time now = real_clock::now();
2211
9f95a23c 2212 int ret = svc.cls->timelog.add(oids[miter->first], entries, nullptr, true, null_yield);
7c673cae
FG
2213 if (ret < 0) {
2214 /* we don't really need to have a special handling for failed cases here,
2215 * as this is just an optimization. */
9f95a23c 2216 lderr(cct) << "ERROR: svc.cls->timelog.add() returned " << ret << dendl;
7c673cae
FG
2217 return ret;
2218 }
2219
2220 real_time expiration = now;
2221 expiration += make_timespan(cct->_conf->rgw_data_log_window);
2222
2223 list<rgw_bucket_shard>& buckets = miter->second.first;
2224 list<rgw_bucket_shard>::iterator liter;
2225 for (liter = buckets.begin(); liter != buckets.end(); ++liter) {
2226 update_renewed(*liter, expiration);
2227 }
2228 }
2229
2230 return 0;
2231}
2232
2233void RGWDataChangesLog::_get_change(const rgw_bucket_shard& bs, ChangeStatusPtr& status)
2234{
9f95a23c 2235 ceph_assert(ceph_mutex_is_locked(lock));
7c673cae
FG
2236 if (!changes.find(bs, status)) {
2237 status = ChangeStatusPtr(new ChangeStatus);
2238 changes.add(bs, status);
2239 }
2240}
2241
2242void RGWDataChangesLog::register_renew(rgw_bucket_shard& bs)
2243{
9f95a23c 2244 std::lock_guard l{lock};
7c673cae
FG
2245 cur_cycle[bs] = true;
2246}
2247
2248void RGWDataChangesLog::update_renewed(rgw_bucket_shard& bs, real_time& expiration)
2249{
9f95a23c 2250 std::lock_guard l{lock};
7c673cae
FG
2251 ChangeStatusPtr status;
2252 _get_change(bs, status);
2253
2254 ldout(cct, 20) << "RGWDataChangesLog::update_renewd() bucket_name=" << bs.bucket.name << " shard_id=" << bs.shard_id << " expiration=" << expiration << dendl;
2255 status->cur_expiration = expiration;
2256}
2257
2258int RGWDataChangesLog::get_log_shard_id(rgw_bucket& bucket, int shard_id) {
2259 rgw_bucket_shard bs(bucket, shard_id);
2260
2261 return choose_oid(bs);
2262}
2263
9f95a23c
TL
2264bool RGWDataChangesLog::filter_bucket(const rgw_bucket& bucket, optional_yield y) const
2265{
2266 if (!bucket_filter) {
2267 return true;
2268 }
2269
2270 return bucket_filter->filter(bucket, y);
2271}
2272
2273int RGWDataChangesLog::add_entry(const RGWBucketInfo& bucket_info, int shard_id) {
2274 auto& bucket = bucket_info.bucket;
2275
2276 if (!filter_bucket(bucket, null_yield)) {
7c673cae 2277 return 0;
9f95a23c 2278 }
7c673cae 2279
91327a77
AA
2280 if (observer) {
2281 observer->on_bucket_changed(bucket.get_key());
2282 }
2283
7c673cae
FG
2284 rgw_bucket_shard bs(bucket, shard_id);
2285
2286 int index = choose_oid(bs);
2287 mark_modified(index, bs);
2288
9f95a23c 2289 lock.lock();
7c673cae
FG
2290
2291 ChangeStatusPtr status;
2292 _get_change(bs, status);
2293
9f95a23c 2294 lock.unlock();
7c673cae
FG
2295
2296 real_time now = real_clock::now();
2297
9f95a23c 2298 status->lock.lock();
7c673cae
FG
2299
2300 ldout(cct, 20) << "RGWDataChangesLog::add_entry() bucket.name=" << bucket.name << " shard_id=" << shard_id << " now=" << now << " cur_expiration=" << status->cur_expiration << dendl;
2301
2302 if (now < status->cur_expiration) {
2303 /* no need to send, recently completed */
9f95a23c 2304 status->lock.unlock();
7c673cae
FG
2305
2306 register_renew(bs);
2307 return 0;
2308 }
2309
2310 RefCountedCond *cond;
2311
2312 if (status->pending) {
2313 cond = status->cond;
2314
11fdf7f2 2315 ceph_assert(cond);
7c673cae
FG
2316
2317 status->cond->get();
9f95a23c 2318 status->lock.unlock();
7c673cae
FG
2319
2320 int ret = cond->wait();
2321 cond->put();
2322 if (!ret) {
2323 register_renew(bs);
2324 }
2325 return ret;
2326 }
2327
2328 status->cond = new RefCountedCond;
2329 status->pending = true;
2330
2331 string& oid = oids[index];
2332 real_time expiration;
2333
2334 int ret;
2335
2336 do {
2337 status->cur_sent = now;
2338
2339 expiration = now;
2340 expiration += ceph::make_timespan(cct->_conf->rgw_data_log_window);
2341
9f95a23c 2342 status->lock.unlock();
7c673cae
FG
2343
2344 bufferlist bl;
2345 rgw_data_change change;
2346 change.entity_type = ENTITY_TYPE_BUCKET;
2347 change.key = bs.get_key();
2348 change.timestamp = now;
11fdf7f2 2349 encode(change, bl);
7c673cae
FG
2350 string section;
2351
2352 ldout(cct, 20) << "RGWDataChangesLog::add_entry() sending update with now=" << now << " cur_expiration=" << expiration << dendl;
2353
9f95a23c 2354 ret = svc.cls->timelog.add(oid, now, section, change.key, bl, null_yield);
7c673cae
FG
2355
2356 now = real_clock::now();
2357
9f95a23c 2358 status->lock.lock();
7c673cae
FG
2359
2360 } while (!ret && real_clock::now() > expiration);
2361
2362 cond = status->cond;
2363
2364 status->pending = false;
2365 status->cur_expiration = status->cur_sent; /* time of when operation started, not completed */
2366 status->cur_expiration += make_timespan(cct->_conf->rgw_data_log_window);
2367 status->cond = NULL;
9f95a23c 2368 status->lock.unlock();
7c673cae
FG
2369
2370 cond->done(ret);
2371 cond->put();
2372
2373 return ret;
2374}
2375
2376int RGWDataChangesLog::list_entries(int shard, const real_time& start_time, const real_time& end_time, int max_entries,
2377 list<rgw_data_change_log_entry>& entries,
2378 const string& marker,
2379 string *out_marker,
2380 bool *truncated) {
31f18b77
FG
2381 if (shard >= num_shards)
2382 return -EINVAL;
7c673cae
FG
2383
2384 list<cls_log_entry> log_entries;
2385
9f95a23c 2386 int ret = svc.cls->timelog.list(oids[shard], start_time, end_time,
7c673cae 2387 max_entries, log_entries, marker,
9f95a23c 2388 out_marker, truncated, null_yield);
7c673cae
FG
2389 if (ret < 0)
2390 return ret;
2391
2392 list<cls_log_entry>::iterator iter;
2393 for (iter = log_entries.begin(); iter != log_entries.end(); ++iter) {
2394 rgw_data_change_log_entry log_entry;
2395 log_entry.log_id = iter->id;
2396 real_time rt = iter->timestamp.to_real_time();
2397 log_entry.log_timestamp = rt;
11fdf7f2 2398 auto liter = iter->data.cbegin();
7c673cae 2399 try {
11fdf7f2 2400 decode(log_entry.entry, liter);
7c673cae
FG
2401 } catch (buffer::error& err) {
2402 lderr(cct) << "ERROR: failed to decode data changes log entry" << dendl;
2403 return -EIO;
2404 }
2405 entries.push_back(log_entry);
2406 }
2407
2408 return 0;
2409}
2410
2411int RGWDataChangesLog::list_entries(const real_time& start_time, const real_time& end_time, int max_entries,
2412 list<rgw_data_change_log_entry>& entries, LogMarker& marker, bool *ptruncated) {
2413 bool truncated;
2414 entries.clear();
2415
2416 for (; marker.shard < num_shards && (int)entries.size() < max_entries;
2417 marker.shard++, marker.marker.clear()) {
2418 int ret = list_entries(marker.shard, start_time, end_time, max_entries - entries.size(), entries,
2419 marker.marker, NULL, &truncated);
2420 if (ret == -ENOENT) {
2421 continue;
2422 }
2423 if (ret < 0) {
2424 return ret;
2425 }
2426 if (truncated) {
2427 *ptruncated = true;
2428 return 0;
2429 }
2430 }
2431
2432 *ptruncated = (marker.shard < num_shards);
2433
2434 return 0;
2435}
2436
2437int RGWDataChangesLog::get_info(int shard_id, RGWDataChangesLogInfo *info)
2438{
2439 if (shard_id >= num_shards)
2440 return -EINVAL;
2441
2442 string oid = oids[shard_id];
2443
2444 cls_log_header header;
2445
9f95a23c 2446 int ret = svc.cls->timelog.info(oid, &header, null_yield);
7c673cae
FG
2447 if ((ret < 0) && (ret != -ENOENT))
2448 return ret;
2449
2450 info->marker = header.max_marker;
2451 info->last_update = header.max_time.to_real_time();
2452
2453 return 0;
2454}
2455
2456int RGWDataChangesLog::trim_entries(int shard_id, const real_time& start_time, const real_time& end_time,
2457 const string& start_marker, const string& end_marker)
2458{
7c673cae
FG
2459 if (shard_id > num_shards)
2460 return -EINVAL;
2461
9f95a23c
TL
2462 return svc.cls->timelog.trim(oids[shard_id], start_time, end_time,
2463 start_marker, end_marker, nullptr, null_yield);
11fdf7f2
TL
2464}
2465
7c673cae
FG
2466bool RGWDataChangesLog::going_down()
2467{
2468 return down_flag;
2469}
2470
2471RGWDataChangesLog::~RGWDataChangesLog() {
2472 down_flag = true;
2473 renew_thread->stop();
2474 renew_thread->join();
2475 delete renew_thread;
2476 delete[] oids;
2477}
2478
2479void *RGWDataChangesLog::ChangesRenewThread::entry() {
9f95a23c 2480 for (;;) {
7c673cae
FG
2481 dout(2) << "RGWDataChangesLog::ChangesRenewThread: start" << dendl;
2482 int r = log->renew_entries();
2483 if (r < 0) {
2484 dout(0) << "ERROR: RGWDataChangesLog::renew_entries returned error r=" << r << dendl;
2485 }
2486
2487 if (log->going_down())
2488 break;
2489
2490 int interval = cct->_conf->rgw_data_log_window * 3 / 4;
9f95a23c
TL
2491 std::unique_lock locker{lock};
2492 cond.wait_for(locker, std::chrono::seconds(interval));
2493 }
7c673cae
FG
2494
2495 return NULL;
2496}
2497
2498void RGWDataChangesLog::ChangesRenewThread::stop()
2499{
9f95a23c
TL
2500 std::lock_guard l{lock};
2501 cond.notify_all();
7c673cae
FG
2502}
2503
2504void RGWDataChangesLog::mark_modified(int shard_id, const rgw_bucket_shard& bs)
2505{
2506 auto key = bs.get_key();
9f95a23c
TL
2507 {
2508 std::shared_lock rl{modified_lock}; // read lock to check for existence
2509 auto shard = modified_shards.find(shard_id);
2510 if (shard != modified_shards.end() && shard->second.count(key)) {
7c673cae
FG
2511 return;
2512 }
2513 }
7c673cae 2514
9f95a23c 2515 std::unique_lock wl{modified_lock}; // write lock for insertion
7c673cae
FG
2516 modified_shards[shard_id].insert(key);
2517}
2518
2519void RGWDataChangesLog::read_clear_modified(map<int, set<string> > &modified)
2520{
9f95a23c 2521 std::unique_lock wl{modified_lock};
7c673cae
FG
2522 modified.swap(modified_shards);
2523 modified_shards.clear();
2524}
2525
2526void RGWBucketCompleteInfo::dump(Formatter *f) const {
2527 encode_json("bucket_info", info, f);
2528 encode_json("attrs", attrs, f);
2529}
2530
2531void RGWBucketCompleteInfo::decode_json(JSONObj *obj) {
2532 JSONDecoder::decode_json("bucket_info", info, obj);
2533 JSONDecoder::decode_json("attrs", attrs, obj);
2534}
2535
9f95a23c 2536class RGWBucketMetadataHandler : public RGWBucketMetadataHandlerBase {
7c673cae 2537public:
9f95a23c
TL
2538 struct Svc {
2539 RGWSI_Bucket *bucket{nullptr};
2540 } svc;
7c673cae 2541
9f95a23c
TL
2542 struct Ctl {
2543 RGWBucketCtl *bucket{nullptr};
2544 } ctl;
7c673cae 2545
9f95a23c 2546 RGWBucketMetadataHandler() {}
7c673cae 2547
9f95a23c
TL
2548 void init(RGWSI_Bucket *bucket_svc,
2549 RGWBucketCtl *bucket_ctl) override {
2550 base_init(bucket_svc->ctx(),
2551 bucket_svc->get_ep_be_handler().get());
2552 svc.bucket = bucket_svc;
2553 ctl.bucket = bucket_ctl;
2554 }
7c673cae 2555
9f95a23c 2556 string get_type() override { return "bucket"; }
7c673cae 2557
9f95a23c
TL
2558 RGWMetadataObject *get_meta_obj(JSONObj *jo, const obj_version& objv, const ceph::real_time& mtime) override {
2559 RGWBucketEntryPoint be;
7c673cae 2560
7c673cae 2561 try {
9f95a23c 2562 decode_json_obj(be, jo);
7c673cae 2563 } catch (JSONDecoder::err& e) {
9f95a23c 2564 return nullptr;
7c673cae
FG
2565 }
2566
9f95a23c
TL
2567 return new RGWBucketEntryMetadataObject(be, objv, mtime);
2568 }
7c673cae 2569
9f95a23c
TL
2570 int do_get(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWMetadataObject **obj, optional_yield y) override {
2571 RGWObjVersionTracker ot;
2572 RGWBucketEntryPoint be;
7c673cae 2573
9f95a23c
TL
2574 real_time mtime;
2575 map<string, bufferlist> attrs;
7c673cae 2576
9f95a23c 2577 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
7c673cae 2578
9f95a23c 2579 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &ot, &mtime, &attrs, y);
7c673cae
FG
2580 if (ret < 0)
2581 return ret;
2582
9f95a23c 2583 RGWBucketEntryMetadataObject *mdo = new RGWBucketEntryMetadataObject(be, ot.read_version, mtime, std::move(attrs));
7c673cae 2584
9f95a23c
TL
2585 *obj = mdo;
2586
2587 return 0;
7c673cae
FG
2588 }
2589
9f95a23c
TL
2590 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2591 RGWMetadataObject *obj,
2592 RGWObjVersionTracker& objv_tracker,
2593 optional_yield y,
2594 RGWMDLogSyncType type) override;
7c673cae 2595
9f95a23c
TL
2596 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
2597 optional_yield y) override {
7c673cae 2598 RGWBucketEntryPoint be;
7c673cae 2599
9f95a23c
TL
2600 real_time orig_mtime;
2601
2602 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
2603
2604 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &objv_tracker, &orig_mtime, nullptr, y);
7c673cae
FG
2605 if (ret < 0)
2606 return ret;
2607
2608 /*
31f18b77 2609 * We're unlinking the bucket but we don't want to update the entrypoint here - we're removing
7c673cae
FG
2610 * it immediately and don't want to invalidate our cached objv_version or the bucket obj removal
2611 * will incorrectly fail.
2612 */
9f95a23c 2613 ret = ctl.bucket->unlink_bucket(be.owner, be.bucket, y, false);
7c673cae 2614 if (ret < 0) {
9f95a23c 2615 lderr(svc.bucket->ctx()) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
7c673cae
FG
2616 }
2617
9f95a23c 2618 ret = svc.bucket->remove_bucket_entrypoint_info(ctx, entry, &objv_tracker, y);
7c673cae 2619 if (ret < 0) {
9f95a23c 2620 lderr(svc.bucket->ctx()) << "could not delete bucket=" << entry << dendl;
7c673cae
FG
2621 }
2622 /* idempotent */
2623 return 0;
2624 }
2625
9f95a23c
TL
2626 int call(std::function<int(RGWSI_Bucket_EP_Ctx& ctx)> f) {
2627 return call(nullopt, f);
7c673cae
FG
2628 }
2629
9f95a23c
TL
2630 int call(std::optional<RGWSI_MetaBackend_CtxParams> bectx_params,
2631 std::function<int(RGWSI_Bucket_EP_Ctx& ctx)> f) {
2632 return be_handler->call(bectx_params, [&](RGWSI_MetaBackend_Handler::Op *op) {
2633 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
2634 return f(ctx);
2635 });
2636 }
2637};
7c673cae 2638
9f95a23c
TL
2639class RGWMetadataHandlerPut_Bucket : public RGWMetadataHandlerPut_SObj
2640{
2641 RGWBucketMetadataHandler *bhandler;
2642 RGWBucketEntryMetadataObject *obj;
2643public:
2644 RGWMetadataHandlerPut_Bucket(RGWBucketMetadataHandler *_handler,
2645 RGWSI_MetaBackend_Handler::Op *op, string& entry,
2646 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
2647 optional_yield y,
2648 RGWMDLogSyncType type) : RGWMetadataHandlerPut_SObj(_handler, op, entry, obj, objv_tracker, y, type),
2649 bhandler(_handler) {
2650 obj = static_cast<RGWBucketEntryMetadataObject *>(_obj);
2651 }
2652 ~RGWMetadataHandlerPut_Bucket() {}
7c673cae 2653
9f95a23c
TL
2654 void encode_obj(bufferlist *bl) override {
2655 obj->get_ep().encode(*bl);
7c673cae
FG
2656 }
2657
9f95a23c
TL
2658 int put_checked() override;
2659 int put_post() override;
2660};
7c673cae 2661
9f95a23c
TL
2662int RGWBucketMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2663 RGWMetadataObject *obj,
2664 RGWObjVersionTracker& objv_tracker,
2665 optional_yield y,
2666 RGWMDLogSyncType type)
2667{
2668 RGWMetadataHandlerPut_Bucket put_op(this, op, entry, obj, objv_tracker, y, type);
2669 return do_put_operate(&put_op);
2670}
7c673cae 2671
9f95a23c
TL
2672int RGWMetadataHandlerPut_Bucket::put_checked()
2673{
2674 RGWBucketEntryMetadataObject *orig_obj = static_cast<RGWBucketEntryMetadataObject *>(old_obj);
7c673cae 2675
9f95a23c
TL
2676 if (orig_obj) {
2677 obj->set_pattrs(&orig_obj->get_attrs());
2678 }
7c673cae 2679
9f95a23c
TL
2680 auto& be = obj->get_ep();
2681 auto mtime = obj->get_mtime();
2682 auto pattrs = obj->get_pattrs();
7c673cae 2683
9f95a23c 2684 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
7c673cae 2685
9f95a23c
TL
2686 return bhandler->svc.bucket->store_bucket_entrypoint_info(ctx, entry,
2687 be,
2688 false,
2689 mtime,
2690 pattrs,
2691 &objv_tracker,
2692 y);
2693}
7c673cae 2694
9f95a23c
TL
2695int RGWMetadataHandlerPut_Bucket::put_post()
2696{
2697 auto& be = obj->get_ep();
7c673cae 2698
9f95a23c 2699 int ret;
7c673cae 2700
9f95a23c
TL
2701 /* link bucket */
2702 if (be.linked) {
2703 ret = bhandler->ctl.bucket->link_bucket(be.owner, be.bucket, be.creation_time, y, false);
2704 } else {
2705 ret = bhandler->ctl.bucket->unlink_bucket(be.owner, be.bucket, y, false);
7c673cae 2706 }
181888fb 2707
9f95a23c
TL
2708 return ret;
2709}
7c673cae 2710
9f95a23c 2711static void get_md5_digest(const RGWBucketEntryPoint *be, string& md5_digest) {
11fdf7f2
TL
2712
2713 char md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
2714 unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
2715 bufferlist bl;
2716
2717 Formatter *f = new JSONFormatter(false);
2718 be->dump(f);
2719 f->flush(bl);
2720
2721 MD5 hash;
2722 hash.Update((const unsigned char *)bl.c_str(), bl.length());
2723 hash.Final(m);
2724
2725 buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, md5);
2726
2727 delete f;
2728
2729 md5_digest = md5;
2730}
2731
2732#define ARCHIVE_META_ATTR RGW_ATTR_PREFIX "zone.archive.info"
2733
2734struct archive_meta_info {
2735 rgw_bucket orig_bucket;
2736
2737 bool from_attrs(CephContext *cct, map<string, bufferlist>& attrs) {
2738 auto iter = attrs.find(ARCHIVE_META_ATTR);
2739 if (iter == attrs.end()) {
2740 return false;
2741 }
2742
2743 auto bliter = iter->second.cbegin();
2744 try {
2745 decode(bliter);
2746 } catch (buffer::error& err) {
2747 ldout(cct, 0) << "ERROR: failed to decode archive meta info" << dendl;
2748 return false;
2749 }
2750
2751 return true;
2752 }
2753
2754 void store_in_attrs(map<string, bufferlist>& attrs) const {
2755 encode(attrs[ARCHIVE_META_ATTR]);
2756 }
2757
2758 void encode(bufferlist& bl) const {
2759 ENCODE_START(1, 1, bl);
2760 encode(orig_bucket, bl);
2761 ENCODE_FINISH(bl);
2762 }
2763
2764 void decode(bufferlist::const_iterator& bl) {
2765 DECODE_START(1, bl);
2766 decode(orig_bucket, bl);
2767 DECODE_FINISH(bl);
2768 }
2769};
2770WRITE_CLASS_ENCODER(archive_meta_info)
2771
2772class RGWArchiveBucketMetadataHandler : public RGWBucketMetadataHandler {
2773public:
9f95a23c
TL
2774 RGWArchiveBucketMetadataHandler() {}
2775
2776 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
2777 optional_yield y) override {
2778 auto cct = svc.bucket->ctx();
2779
2780 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
2781
2782 ldout(cct, 5) << "SKIP: bucket removal is not allowed on archive zone: bucket:" << entry << " ... proceeding to rename" << dendl;
11fdf7f2
TL
2783
2784 string tenant_name, bucket_name;
2785 parse_bucket(entry, &tenant_name, &bucket_name);
9f95a23c
TL
2786 rgw_bucket entry_bucket;
2787 entry_bucket.tenant = tenant_name;
2788 entry_bucket.name = bucket_name;
11fdf7f2
TL
2789
2790 real_time mtime;
2791
2792 /* read original entrypoint */
2793
2794 RGWBucketEntryPoint be;
11fdf7f2 2795 map<string, bufferlist> attrs;
9f95a23c 2796 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &objv_tracker, &mtime, &attrs, y);
11fdf7f2
TL
2797 if (ret < 0) {
2798 return ret;
2799 }
2800
9f95a23c 2801 string bi_meta_name = RGWSI_Bucket::get_bi_meta_key(be.bucket);
11fdf7f2
TL
2802
2803 /* read original bucket instance info */
2804
2805 map<string, bufferlist> attrs_m;
2806 ceph::real_time orig_mtime;
2807 RGWBucketInfo old_bi;
2808
9f95a23c
TL
2809 ret = ctl.bucket->read_bucket_instance_info(be.bucket, &old_bi, y, RGWBucketCtl::BucketInstance::GetParams()
2810 .set_mtime(&orig_mtime)
2811 .set_attrs(&attrs_m));
11fdf7f2
TL
2812 if (ret < 0) {
2813 return ret;
2814 }
2815
2816 archive_meta_info ami;
2817
9f95a23c 2818 if (!ami.from_attrs(svc.bucket->ctx(), attrs_m)) {
11fdf7f2
TL
2819 ami.orig_bucket = old_bi.bucket;
2820 ami.store_in_attrs(attrs_m);
2821 }
2822
2823 /* generate a new bucket instance. We could have avoided this if we could just point a new
2824 * bucket entry point to the old bucket instance, however, due to limitation in the way
2825 * we index buckets under the user, bucket entrypoint and bucket instance of the same
2826 * bucket need to have the same name, so we need to copy the old bucket instance into
2827 * to a new entry with the new name
2828 */
2829
2830 string new_bucket_name;
2831
2832 RGWBucketInfo new_bi = old_bi;
2833 RGWBucketEntryPoint new_be = be;
2834
2835 string md5_digest;
2836
2837 get_md5_digest(&new_be, md5_digest);
2838 new_bucket_name = ami.orig_bucket.name + "-deleted-" + md5_digest;
2839
2840 new_bi.bucket.name = new_bucket_name;
2841 new_bi.objv_tracker.clear();
2842
2843 new_be.bucket.name = new_bucket_name;
2844
9f95a23c
TL
2845 ret = ctl.bucket->store_bucket_instance_info(be.bucket, new_bi, y, RGWBucketCtl::BucketInstance::PutParams()
2846 .set_exclusive(false)
2847 .set_mtime(orig_mtime)
2848 .set_attrs(&attrs_m)
2849 .set_orig_info(&old_bi));
11fdf7f2 2850 if (ret < 0) {
9f95a23c 2851 ldout(cct, 0) << "ERROR: failed to put new bucket instance info for bucket=" << new_bi.bucket << " ret=" << ret << dendl;
11fdf7f2
TL
2852 return ret;
2853 }
2854
2855 /* store a new entrypoint */
2856
2857 RGWObjVersionTracker ot;
9f95a23c 2858 ot.generate_new_write_ver(cct);
11fdf7f2 2859
9f95a23c
TL
2860 ret = svc.bucket->store_bucket_entrypoint_info(ctx, RGWSI_Bucket::get_entrypoint_meta_key(new_be.bucket),
2861 new_be, true, mtime, &attrs, nullptr, y);
11fdf7f2 2862 if (ret < 0) {
9f95a23c 2863 ldout(cct, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be.bucket << " ret=" << ret << dendl;
11fdf7f2
TL
2864 return ret;
2865 }
2866
2867 /* link new bucket */
2868
9f95a23c 2869 ret = ctl.bucket->link_bucket(new_be.owner, new_be.bucket, new_be.creation_time, y, false);
11fdf7f2 2870 if (ret < 0) {
9f95a23c 2871 ldout(cct, 0) << "ERROR: failed to link new bucket for bucket=" << new_be.bucket << " ret=" << ret << dendl;
11fdf7f2
TL
2872 return ret;
2873 }
2874
2875 /* clean up old stuff */
2876
9f95a23c 2877 ret = ctl.bucket->unlink_bucket(be.owner, entry_bucket, y, false);
11fdf7f2 2878 if (ret < 0) {
9f95a23c 2879 lderr(cct) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
11fdf7f2
TL
2880 }
2881
2882 // if (ret == -ECANCELED) it means that there was a race here, and someone
2883 // wrote to the bucket entrypoint just before we removed it. The question is
2884 // whether it was a newly created bucket entrypoint ... in which case we
2885 // should ignore the error and move forward, or whether it is a higher version
2886 // of the same bucket instance ... in which we should retry
9f95a23c
TL
2887 ret = svc.bucket->remove_bucket_entrypoint_info(ctx,
2888 RGWSI_Bucket::get_entrypoint_meta_key(be.bucket),
2889 &objv_tracker,
2890 y);
2891 if (ret < 0) {
2892 ldout(cct, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be.bucket << " ret=" << ret << dendl;
2893 return ret;
2894 }
2895
2896 ret = ctl.bucket->remove_bucket_instance_info(be.bucket, old_bi, y);
11fdf7f2 2897 if (ret < 0) {
9f95a23c 2898 lderr(cct) << "could not delete bucket=" << entry << dendl;
11fdf7f2
TL
2899 }
2900
11fdf7f2
TL
2901
2902 /* idempotent */
2903
2904 return 0;
2905 }
2906
9f95a23c
TL
2907 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2908 RGWMetadataObject *obj,
2909 RGWObjVersionTracker& objv_tracker,
2910 optional_yield y,
2911 RGWMDLogSyncType type) override {
11fdf7f2
TL
2912 if (entry.find("-deleted-") != string::npos) {
2913 RGWObjVersionTracker ot;
2914 RGWMetadataObject *robj;
9f95a23c 2915 int ret = do_get(op, entry, &robj, y);
11fdf7f2
TL
2916 if (ret != -ENOENT) {
2917 if (ret < 0) {
2918 return ret;
2919 }
2920 ot.read_version = robj->get_version();
2921 delete robj;
2922
9f95a23c 2923 ret = do_remove(op, entry, ot, y);
11fdf7f2
TL
2924 if (ret < 0) {
2925 return ret;
2926 }
2927 }
2928 }
2929
9f95a23c
TL
2930 return RGWBucketMetadataHandler::do_put(op, entry, obj,
2931 objv_tracker, y, type);
11fdf7f2
TL
2932 }
2933
2934};
2935
9f95a23c
TL
2936class RGWBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandlerBase {
2937 int read_bucket_instance_entry(RGWSI_Bucket_BI_Ctx& ctx,
2938 const string& entry,
2939 RGWBucketCompleteInfo *bi,
2940 ceph::real_time *pmtime,
2941 optional_yield y) {
2942 return svc.bucket->read_bucket_instance_info(ctx,
2943 entry,
2944 &bi->info,
2945 pmtime, &bi->attrs,
2946 y);
2947 }
7c673cae
FG
2948
2949public:
9f95a23c
TL
2950 struct Svc {
2951 RGWSI_Zone *zone{nullptr};
2952 RGWSI_Bucket *bucket{nullptr};
2953 RGWSI_BucketIndex *bi{nullptr};
2954 } svc;
2955
2956 RGWBucketInstanceMetadataHandler() {}
2957
2958 void init(RGWSI_Zone *zone_svc,
2959 RGWSI_Bucket *bucket_svc,
2960 RGWSI_BucketIndex *bi_svc) {
2961 base_init(bucket_svc->ctx(),
2962 bucket_svc->get_bi_be_handler().get());
2963 svc.zone = zone_svc;
2964 svc.bucket = bucket_svc;
2965 svc.bi = bi_svc;
2966 }
2967
7c673cae
FG
2968 string get_type() override { return "bucket.instance"; }
2969
9f95a23c 2970 RGWMetadataObject *get_meta_obj(JSONObj *jo, const obj_version& objv, const ceph::real_time& mtime) override {
7c673cae
FG
2971 RGWBucketCompleteInfo bci;
2972
9f95a23c
TL
2973 try {
2974 decode_json_obj(bci, jo);
2975 } catch (JSONDecoder::err& e) {
2976 return nullptr;
2977 }
2978
2979 return new RGWBucketInstanceMetadataObject(bci, objv, mtime);
2980 }
2981
2982 int do_get(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWMetadataObject **obj, optional_yield y) override {
2983 RGWBucketCompleteInfo bci;
7c673cae 2984 real_time mtime;
7c673cae 2985
9f95a23c
TL
2986 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2987
2988 int ret = svc.bucket->read_bucket_instance_info(ctx, entry, &bci.info, &mtime, &bci.attrs, y);
7c673cae
FG
2989 if (ret < 0)
2990 return ret;
2991
2992 RGWBucketInstanceMetadataObject *mdo = new RGWBucketInstanceMetadataObject(bci, bci.info.objv_tracker.read_version, mtime);
2993
2994 *obj = mdo;
2995
2996 return 0;
2997 }
2998
9f95a23c
TL
2999 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
3000 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
3001 optional_yield y,
3002 RGWMDLogSyncType sync_type) override;
7c673cae 3003
9f95a23c
TL
3004 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
3005 optional_yield y) override {
3006 RGWBucketCompleteInfo bci;
7c673cae 3007
9f95a23c
TL
3008 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
3009
3010 int ret = read_bucket_instance_entry(ctx, entry, &bci, nullptr, y);
3011 if (ret < 0 && ret != -ENOENT)
7c673cae
FG
3012 return ret;
3013
9f95a23c
TL
3014 return svc.bucket->remove_bucket_instance_info(ctx, entry, bci.info, &bci.info.objv_tracker, y);
3015 }
7c673cae 3016
9f95a23c
TL
3017 int call(std::function<int(RGWSI_Bucket_BI_Ctx& ctx)> f) {
3018 return call(nullopt, f);
3019 }
c07f9fc5 3020
9f95a23c
TL
3021 int call(std::optional<RGWSI_MetaBackend_CtxParams> bectx_params,
3022 std::function<int(RGWSI_Bucket_BI_Ctx& ctx)> f) {
3023 return be_handler->call(bectx_params, [&](RGWSI_MetaBackend_Handler::Op *op) {
3024 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
3025 return f(ctx);
3026 });
3027 }
3028};
c07f9fc5 3029
9f95a23c
TL
3030class RGWMetadataHandlerPut_BucketInstance : public RGWMetadataHandlerPut_SObj
3031{
3032 CephContext *cct;
3033 RGWBucketInstanceMetadataHandler *bihandler;
3034 RGWBucketInstanceMetadataObject *obj;
3035public:
3036 RGWMetadataHandlerPut_BucketInstance(CephContext *cct,
3037 RGWBucketInstanceMetadataHandler *_handler,
3038 RGWSI_MetaBackend_Handler::Op *_op, string& entry,
3039 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
3040 optional_yield y,
3041 RGWMDLogSyncType type) : RGWMetadataHandlerPut_SObj(_handler, _op, entry, obj, objv_tracker, y, type),
3042 bihandler(_handler) {
3043 obj = static_cast<RGWBucketInstanceMetadataObject *>(_obj);
c07f9fc5 3044
9f95a23c
TL
3045 auto& bci = obj->get_bci();
3046 obj->set_pattrs(&bci.attrs);
3047 }
7c673cae 3048
9f95a23c
TL
3049 void encode_obj(bufferlist *bl) override {
3050 obj->get_bucket_info().encode(*bl);
3051 }
7c673cae 3052
9f95a23c
TL
3053 int put_check() override;
3054 int put_checked() override;
3055 int put_post() override;
3056};
7c673cae 3057
9f95a23c
TL
3058int RGWBucketInstanceMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op,
3059 string& entry,
3060 RGWMetadataObject *obj,
3061 RGWObjVersionTracker& objv_tracker,
3062 optional_yield y,
3063 RGWMDLogSyncType type)
3064{
3065 RGWMetadataHandlerPut_BucketInstance put_op(svc.bucket->ctx(), this, op, entry, obj,
3066 objv_tracker, y, type);
3067 return do_put_operate(&put_op);
3068}
7c673cae 3069
9f95a23c
TL
3070int RGWMetadataHandlerPut_BucketInstance::put_check()
3071{
3072 int ret;
7c673cae 3073
9f95a23c 3074 RGWBucketCompleteInfo& bci = obj->get_bci();
7c673cae 3075
9f95a23c 3076 RGWBucketInstanceMetadataObject *orig_obj = static_cast<RGWBucketInstanceMetadataObject *>(old_obj);
7c673cae 3077
9f95a23c 3078 RGWBucketCompleteInfo *old_bci = (orig_obj ? &orig_obj->get_bci() : nullptr);
7c673cae 3079
9f95a23c 3080 bool exists = (!!orig_obj);
7c673cae 3081
9f95a23c
TL
3082 if (!exists || old_bci->info.bucket.bucket_id != bci.info.bucket.bucket_id) {
3083 /* a new bucket, we need to select a new bucket placement for it */
3084 string tenant_name;
3085 string bucket_name;
3086 string bucket_instance;
3087 parse_bucket(entry, &tenant_name, &bucket_name, &bucket_instance);
7c673cae 3088
9f95a23c
TL
3089 RGWZonePlacementInfo rule_info;
3090 bci.info.bucket.name = bucket_name;
3091 bci.info.bucket.bucket_id = bucket_instance;
3092 bci.info.bucket.tenant = tenant_name;
3093 // if the sync module never writes data, don't require the zone to specify all placement targets
3094 if (bihandler->svc.zone->sync_module_supports_writes()) {
3095 ret = bihandler->svc.zone->select_bucket_location_by_rule(bci.info.placement_rule, &rule_info);
3096 if (ret < 0) {
3097 ldout(cct, 0) << "ERROR: select_bucket_placement() returned " << ret << dendl;
3098 return ret;
3099 }
3100 }
3101 bci.info.index_type = rule_info.index_type;
3102 } else {
3103 /* existing bucket, keep its placement */
3104 bci.info.bucket.explicit_placement = old_bci->info.bucket.explicit_placement;
3105 bci.info.placement_rule = old_bci->info.placement_rule;
7c673cae
FG
3106 }
3107
9f95a23c
TL
3108 /* record the read version (if any), store the new version */
3109 bci.info.objv_tracker.read_version = objv_tracker.read_version;
3110 bci.info.objv_tracker.write_version = objv_tracker.write_version;
7c673cae 3111
9f95a23c
TL
3112 return 0;
3113}
7c673cae 3114
9f95a23c
TL
3115int RGWMetadataHandlerPut_BucketInstance::put_checked()
3116{
3117 RGWBucketInstanceMetadataObject *orig_obj = static_cast<RGWBucketInstanceMetadataObject *>(old_obj);
7c673cae 3118
9f95a23c 3119 RGWBucketInfo *orig_info = (orig_obj ? &orig_obj->get_bucket_info() : nullptr);
7c673cae 3120
9f95a23c
TL
3121 auto& info = obj->get_bucket_info();
3122 auto mtime = obj->get_mtime();
3123 auto pattrs = obj->get_pattrs();
7c673cae 3124
9f95a23c 3125 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
7c673cae 3126
9f95a23c
TL
3127 return bihandler->svc.bucket->store_bucket_instance_info(ctx,
3128 entry,
3129 info,
3130 orig_info,
3131 false,
3132 mtime,
3133 pattrs,
3134 y);
3135}
7c673cae 3136
9f95a23c
TL
3137int RGWMetadataHandlerPut_BucketInstance::put_post()
3138{
3139 RGWBucketCompleteInfo& bci = obj->get_bci();
7c673cae 3140
9f95a23c 3141 objv_tracker = bci.info.objv_tracker;
7c673cae 3142
9f95a23c
TL
3143 int ret = bihandler->svc.bi->init_index(bci.info);
3144 if (ret < 0) {
3145 return ret;
3146 }
3147
3148 return STATUS_APPLIED;
3149}
7c673cae 3150
9f95a23c
TL
3151class RGWArchiveBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandler {
3152public:
3153 RGWArchiveBucketInstanceMetadataHandler() {}
7c673cae 3154
9f95a23c
TL
3155 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker, optional_yield y) override {
3156 ldout(cct, 0) << "SKIP: bucket instance removal is not allowed on archive zone: bucket.instance:" << entry << dendl;
3157 return 0;
3158 }
3159};
3160
3161bool RGWBucketCtl::DataLogFilter::filter(const rgw_bucket& bucket, optional_yield y) const
3162{
3163 return bucket_ctl->bucket_exports_data(bucket, null_yield);
3164}
3165
3166RGWBucketCtl::RGWBucketCtl(RGWSI_Zone *zone_svc,
3167 RGWSI_Bucket *bucket_svc,
3168 RGWSI_Bucket_Sync *bucket_sync_svc,
3169 RGWSI_BucketIndex *bi_svc) : cct(zone_svc->ctx()),
3170 datalog_filter(this)
3171{
3172 svc.zone = zone_svc;
3173 svc.bucket = bucket_svc;
3174 svc.bucket_sync = bucket_sync_svc;
3175 svc.bi = bi_svc;
3176}
3177
3178void RGWBucketCtl::init(RGWUserCtl *user_ctl,
3179 RGWBucketMetadataHandler *_bm_handler,
3180 RGWBucketInstanceMetadataHandler *_bmi_handler,
3181 RGWDataChangesLog *datalog)
3182{
3183 ctl.user = user_ctl;
3184
3185 bm_handler = _bm_handler;
3186 bmi_handler = _bmi_handler;
3187
3188 bucket_be_handler = bm_handler->get_be_handler();
3189 bi_be_handler = bmi_handler->get_be_handler();
3190
3191 datalog->set_bucket_filter(&datalog_filter);
3192}
3193
3194int RGWBucketCtl::call(std::function<int(RGWSI_Bucket_X_Ctx& ctx)> f) {
3195 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ep_ctx) {
3196 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& bi_ctx) {
3197 RGWSI_Bucket_X_Ctx ctx{ep_ctx, bi_ctx};
3198 return f(ctx);
3199 });
3200 });
3201}
3202
3203int RGWBucketCtl::read_bucket_entrypoint_info(const rgw_bucket& bucket,
3204 RGWBucketEntryPoint *info,
3205 optional_yield y,
3206 const Bucket::GetParams& params)
3207{
3208 return bm_handler->call(params.bectx_params, [&](RGWSI_Bucket_EP_Ctx& ctx) {
3209 return svc.bucket->read_bucket_entrypoint_info(ctx,
3210 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
3211 info,
3212 params.objv_tracker,
3213 params.mtime,
3214 params.attrs,
3215 y,
3216 params.cache_info,
3217 params.refresh_version);
3218 });
3219}
3220
3221int RGWBucketCtl::store_bucket_entrypoint_info(const rgw_bucket& bucket,
3222 RGWBucketEntryPoint& info,
3223 optional_yield y,
3224 const Bucket::PutParams& params)
3225{
3226 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
3227 return svc.bucket->store_bucket_entrypoint_info(ctx,
3228 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
3229 info,
3230 params.exclusive,
3231 params.mtime,
3232 params.attrs,
3233 params.objv_tracker,
3234 y);
3235 });
3236}
3237
3238int RGWBucketCtl::remove_bucket_entrypoint_info(const rgw_bucket& bucket,
3239 optional_yield y,
3240 const Bucket::RemoveParams& params)
3241{
3242 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
3243 return svc.bucket->remove_bucket_entrypoint_info(ctx,
3244 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
3245 params.objv_tracker,
3246 y);
3247 });
3248}
3249
3250int RGWBucketCtl::read_bucket_instance_info(const rgw_bucket& bucket,
3251 RGWBucketInfo *info,
3252 optional_yield y,
3253 const BucketInstance::GetParams& params)
3254{
3255 int ret = bmi_handler->call(params.bectx_params, [&](RGWSI_Bucket_BI_Ctx& ctx) {
3256 return svc.bucket->read_bucket_instance_info(ctx,
3257 RGWSI_Bucket::get_bi_meta_key(bucket),
3258 info,
3259 params.mtime,
3260 params.attrs,
3261 y,
3262 params.cache_info,
3263 params.refresh_version);
3264 });
3265
3266 if (ret < 0) {
3267 return ret;
3268 }
3269
3270 if (params.objv_tracker) {
3271 *params.objv_tracker = info->objv_tracker;
3272 }
3273
3274 return 0;
3275}
3276
3277int RGWBucketCtl::read_bucket_info(const rgw_bucket& bucket,
3278 RGWBucketInfo *info,
3279 optional_yield y,
3280 const BucketInstance::GetParams& params,
3281 RGWObjVersionTracker *ep_objv_tracker)
3282{
3283 const rgw_bucket *b = &bucket;
3284
3285 std::optional<RGWBucketEntryPoint> ep;
3286
3287 if (b->bucket_id.empty()) {
3288 ep.emplace();
3289
3290 int r = read_bucket_entrypoint_info(*b, &(*ep), y, RGWBucketCtl::Bucket::GetParams()
3291 .set_bectx_params(params.bectx_params)
3292 .set_objv_tracker(ep_objv_tracker));
3293 if (r < 0) {
3294 return r;
7c673cae
FG
3295 }
3296
9f95a23c
TL
3297 b = &ep->bucket;
3298 }
3299
3300 int ret = bmi_handler->call(params.bectx_params, [&](RGWSI_Bucket_BI_Ctx& ctx) {
3301 return svc.bucket->read_bucket_instance_info(ctx,
3302 RGWSI_Bucket::get_bi_meta_key(*b),
3303 info,
3304 params.mtime,
3305 params.attrs,
3306 y,
3307 params.cache_info,
3308 params.refresh_version);
3309 });
3310
3311 if (ret < 0) {
3312 return ret;
3313 }
3314
3315 if (params.objv_tracker) {
3316 *params.objv_tracker = info->objv_tracker;
3317 }
3318
3319 return 0;
3320}
3321
3322int RGWBucketCtl::do_store_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
3323 const rgw_bucket& bucket,
3324 RGWBucketInfo& info,
3325 optional_yield y,
3326 const BucketInstance::PutParams& params)
3327{
3328 if (params.objv_tracker) {
3329 info.objv_tracker = *params.objv_tracker;
3330 }
3331
3332 return svc.bucket->store_bucket_instance_info(ctx,
3333 RGWSI_Bucket::get_bi_meta_key(bucket),
3334 info,
3335 params.orig_info,
3336 params.exclusive,
3337 params.mtime,
3338 params.attrs,
3339 y);
3340}
3341
3342int RGWBucketCtl::store_bucket_instance_info(const rgw_bucket& bucket,
3343 RGWBucketInfo& info,
3344 optional_yield y,
3345 const BucketInstance::PutParams& params)
3346{
3347 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& ctx) {
3348 return do_store_bucket_instance_info(ctx, bucket, info, y, params);
3349 });
3350}
3351
3352int RGWBucketCtl::remove_bucket_instance_info(const rgw_bucket& bucket,
3353 RGWBucketInfo& info,
3354 optional_yield y,
3355 const BucketInstance::RemoveParams& params)
3356{
3357 if (params.objv_tracker) {
3358 info.objv_tracker = *params.objv_tracker;
3359 }
3360
3361 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& ctx) {
3362 return svc.bucket->remove_bucket_instance_info(ctx,
3363 RGWSI_Bucket::get_bi_meta_key(bucket),
3364 info,
3365 &info.objv_tracker,
3366 y);
3367 });
3368}
3369
3370int RGWBucketCtl::do_store_linked_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
3371 RGWBucketInfo& info,
3372 RGWBucketInfo *orig_info,
3373 bool exclusive, real_time mtime,
3374 obj_version *pep_objv,
3375 map<string, bufferlist> *pattrs,
3376 bool create_entry_point,
3377 optional_yield y)
3378{
3379 bool create_head = !info.has_instance_obj || create_entry_point;
3380
3381 int ret = svc.bucket->store_bucket_instance_info(ctx.bi,
3382 RGWSI_Bucket::get_bi_meta_key(info.bucket),
3383 info,
3384 orig_info,
3385 exclusive,
3386 mtime, pattrs,
3387 y);
3388 if (ret < 0) {
3389 return ret;
3390 }
3391
3392 if (!create_head)
3393 return 0; /* done! */
3394
3395 RGWBucketEntryPoint entry_point;
3396 entry_point.bucket = info.bucket;
3397 entry_point.owner = info.owner;
3398 entry_point.creation_time = info.creation_time;
3399 entry_point.linked = true;
3400 RGWObjVersionTracker ot;
3401 if (pep_objv && !pep_objv->tag.empty()) {
3402 ot.write_version = *pep_objv;
3403 } else {
3404 ot.generate_new_write_ver(cct);
3405 if (pep_objv) {
3406 *pep_objv = ot.write_version;
3407 }
3408 }
3409 ret = svc.bucket->store_bucket_entrypoint_info(ctx.ep,
3410 RGWSI_Bucket::get_entrypoint_meta_key(info.bucket),
3411 entry_point,
3412 exclusive,
3413 mtime,
3414 pattrs,
3415 &ot,
3416 y);
3417 if (ret < 0)
3418 return ret;
3419
3420 return 0;
3421}
3422int RGWBucketCtl::convert_old_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
3423 const rgw_bucket& bucket,
3424 optional_yield y)
3425{
3426 RGWBucketEntryPoint entry_point;
3427 real_time ep_mtime;
3428 RGWObjVersionTracker ot;
3429 map<string, bufferlist> attrs;
3430 RGWBucketInfo info;
3431 auto cct = svc.bucket->ctx();
3432
3433 ldout(cct, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket << dendl;
3434
3435 int ret = svc.bucket->read_bucket_entrypoint_info(ctx.ep,
3436 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
3437 &entry_point, &ot, &ep_mtime, &attrs, y);
3438 if (ret < 0) {
3439 ldout(cct, 0) << "ERROR: get_bucket_entrypoint_info() returned " << ret << " bucket=" << bucket << dendl;
3440 return ret;
3441 }
3442
3443 if (!entry_point.has_bucket_info) {
3444 /* already converted! */
7c673cae
FG
3445 return 0;
3446 }
3447
9f95a23c
TL
3448 info = entry_point.old_bucket_info;
3449
3450 ot.generate_new_write_ver(cct);
3451
3452 ret = do_store_linked_bucket_info(ctx, info, nullptr, false, ep_mtime, &ot.write_version, &attrs, true, y);
3453 if (ret < 0) {
3454 ldout(cct, 0) << "ERROR: failed to put_linked_bucket_info(): " << ret << dendl;
3455 return ret;
7c673cae
FG
3456 }
3457
9f95a23c
TL
3458 return 0;
3459}
3460
3461int RGWBucketCtl::set_bucket_instance_attrs(RGWBucketInfo& bucket_info,
3462 map<string, bufferlist>& attrs,
3463 RGWObjVersionTracker *objv_tracker,
3464 optional_yield y)
3465{
3466 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
3467 rgw_bucket& bucket = bucket_info.bucket;
3468
3469 if (!bucket_info.has_instance_obj) {
3470 /* an old bucket object, need to convert it */
3471 int ret = convert_old_bucket_info(ctx, bucket, y);
3472 if (ret < 0) {
3473 ldout(cct, 0) << "ERROR: failed converting old bucket info: " << ret << dendl;
3474 return ret;
3475 }
3476 }
3477
3478 return do_store_bucket_instance_info(ctx.bi,
3479 bucket,
3480 bucket_info,
3481 y,
3482 BucketInstance::PutParams().set_attrs(&attrs)
3483 .set_objv_tracker(objv_tracker)
3484 .set_orig_info(&bucket_info));
3485 });
3486}
3487
3488
3489int RGWBucketCtl::link_bucket(const rgw_user& user_id,
3490 const rgw_bucket& bucket,
3491 ceph::real_time creation_time,
3492 optional_yield y,
3493 bool update_entrypoint,
3494 rgw_ep_info *pinfo)
3495{
3496 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
3497 return do_link_bucket(ctx, user_id, bucket, creation_time, y,
3498 update_entrypoint, pinfo);
3499 });
3500}
3501
3502int RGWBucketCtl::do_link_bucket(RGWSI_Bucket_EP_Ctx& ctx,
3503 const rgw_user& user_id,
3504 const rgw_bucket& bucket,
3505 ceph::real_time creation_time,
3506 optional_yield y,
3507 bool update_entrypoint,
3508 rgw_ep_info *pinfo)
3509{
3510 int ret;
3511
3512 RGWBucketEntryPoint ep;
3513 RGWObjVersionTracker ot;
3514 RGWObjVersionTracker& rot = (pinfo) ? pinfo->ep_objv : ot;
3515 map<string, bufferlist> attrs, *pattrs = nullptr;
3516 string meta_key;
3517
3518 if (update_entrypoint) {
3519 meta_key = RGWSI_Bucket::get_entrypoint_meta_key(bucket);
3520 if (pinfo) {
3521 ep = pinfo->ep;
3522 pattrs = &pinfo->attrs;
3523 } else {
3524 ret = svc.bucket->read_bucket_entrypoint_info(ctx,
3525 meta_key,
3526 &ep, &rot,
3527 nullptr, &attrs,
3528 y);
3529 if (ret < 0 && ret != -ENOENT) {
3530 ldout(cct, 0) << "ERROR: store->get_bucket_entrypoint_info() returned: "
3531 << cpp_strerror(-ret) << dendl;
3532 }
3533 pattrs = &attrs;
3534 }
181888fb
FG
3535 }
3536
9f95a23c
TL
3537 ret = ctl.user->add_bucket(user_id, bucket, creation_time);
3538 if (ret < 0) {
3539 ldout(cct, 0) << "ERROR: error adding bucket to user directory:"
3540 << " user=" << user_id
3541 << " bucket=" << bucket
3542 << " err=" << cpp_strerror(-ret)
3543 << dendl;
3544 goto done_err;
7c673cae 3545 }
7c673cae 3546
9f95a23c
TL
3547 if (!update_entrypoint)
3548 return 0;
3549
3550 ep.linked = true;
3551 ep.owner = user_id;
3552 ep.bucket = bucket;
3553 ret = svc.bucket->store_bucket_entrypoint_info(
3554 ctx, meta_key, ep, false, real_time(), pattrs, &rot, y);
3555 if (ret < 0)
3556 goto done_err;
3557
3558 return 0;
3559
3560done_err:
3561 int r = do_unlink_bucket(ctx, user_id, bucket, y, true);
3562 if (r < 0) {
3563 ldout(cct, 0) << "ERROR: failed unlinking bucket on error cleanup: "
3564 << cpp_strerror(-r) << dendl;
3565 }
3566 return ret;
3567}
3568
3569int RGWBucketCtl::unlink_bucket(const rgw_user& user_id, const rgw_bucket& bucket, optional_yield y, bool update_entrypoint)
3570{
3571 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
3572 return do_unlink_bucket(ctx, user_id, bucket, y, update_entrypoint);
3573 });
3574}
3575
3576int RGWBucketCtl::do_unlink_bucket(RGWSI_Bucket_EP_Ctx& ctx,
3577 const rgw_user& user_id,
3578 const rgw_bucket& bucket,
3579 optional_yield y,
3580 bool update_entrypoint)
3581{
3582 int ret = ctl.user->remove_bucket(user_id, bucket);
3583 if (ret < 0) {
3584 ldout(cct, 0) << "ERROR: error removing bucket from directory: "
3585 << cpp_strerror(-ret)<< dendl;
3586 }
3587
3588 if (!update_entrypoint)
3589 return 0;
3590
3591 RGWBucketEntryPoint ep;
3592 RGWObjVersionTracker ot;
3593 map<string, bufferlist> attrs;
3594 string meta_key = RGWSI_Bucket::get_entrypoint_meta_key(bucket);
3595 ret = svc.bucket->read_bucket_entrypoint_info(ctx, meta_key, &ep, &ot, nullptr, &attrs, y);
3596 if (ret == -ENOENT)
3597 return 0;
3598 if (ret < 0)
3599 return ret;
11fdf7f2 3600
9f95a23c 3601 if (!ep.linked)
11fdf7f2 3602 return 0;
9f95a23c
TL
3603
3604 if (ep.owner != user_id) {
3605 ldout(cct, 0) << "bucket entry point user mismatch, can't unlink bucket: " << ep.owner << " != " << user_id << dendl;
3606 return -EINVAL;
11fdf7f2 3607 }
11fdf7f2 3608
9f95a23c
TL
3609 ep.linked = false;
3610 return svc.bucket->store_bucket_entrypoint_info(ctx, meta_key, ep, false, real_time(), &attrs, &ot, y);
3611}
3612
3613int RGWBucketCtl::set_acl(ACLOwner& owner, rgw_bucket& bucket,
3614 RGWBucketInfo& bucket_info, bufferlist& bl,
3615 optional_yield y)
3616{
3617 // set owner and acl
3618 bucket_info.owner = owner.get_id();
3619 std::map<std::string, bufferlist> attrs{{RGW_ATTR_ACL, bl}};
3620
3621 int r = store_bucket_instance_info(bucket, bucket_info, y,
3622 BucketInstance::PutParams().set_attrs(&attrs));
3623 if (r < 0) {
3624 cerr << "ERROR: failed to set bucket owner: " << cpp_strerror(-r) << std::endl;
3625 return r;
3626 }
3627
3628 return 0;
3629}
3630
3631// TODO: remove RGWRados dependency for bucket listing
3632int RGWBucketCtl::chown(rgw::sal::RGWRadosStore *store, RGWBucketInfo& bucket_info,
3633 const rgw_user& user_id, const std::string& display_name,
3634 const std::string& marker, optional_yield y)
3635{
3636 RGWObjectCtx obj_ctx(store);
3637 std::vector<rgw_bucket_dir_entry> objs;
3638 map<string, bool> common_prefixes;
3639
3640 RGWRados::Bucket target(store->getRados(), bucket_info);
3641 RGWRados::Bucket::List list_op(&target);
3642
3643 list_op.params.list_versions = true;
3644 list_op.params.allow_unordered = true;
3645 list_op.params.marker = marker;
3646
3647 bool is_truncated = false;
3648 int count = 0;
3649 int max_entries = 1000;
3650
3651 //Loop through objects and update object acls to point to bucket owner
3652
3653 do {
3654 objs.clear();
3655 int ret = list_op.list_objects(max_entries, &objs, &common_prefixes, &is_truncated, y);
3656 if (ret < 0) {
3657 ldout(store->ctx(), 0) << "ERROR: list objects failed: " << cpp_strerror(-ret) << dendl;
3658 return ret;
3659 }
3660
3661 list_op.params.marker = list_op.get_next_marker();
3662 count += objs.size();
3663
3664 for (const auto& obj : objs) {
3665
3666 rgw_obj r_obj(bucket_info.bucket, obj.key);
3667 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, r_obj);
3668 RGWRados::Object::Read read_op(&op_target);
3669
3670 map<string, bufferlist> attrs;
3671 read_op.params.attrs = &attrs;
3672 ret = read_op.prepare(y);
3673 if (ret < 0){
3674 ldout(store->ctx(), 0) << "ERROR: failed to read object " << obj.key.name << cpp_strerror(-ret) << dendl;
3675 continue;
3676 }
3677 const auto& aiter = attrs.find(RGW_ATTR_ACL);
3678 if (aiter == attrs.end()) {
3679 ldout(store->ctx(), 0) << "ERROR: no acls found for object " << obj.key.name << " .Continuing with next object." << dendl;
3680 continue;
3681 } else {
3682 bufferlist& bl = aiter->second;
3683 RGWAccessControlPolicy policy(store->ctx());
3684 ACLOwner owner;
3685 try {
3686 decode(policy, bl);
3687 owner = policy.get_owner();
3688 } catch (buffer::error& err) {
3689 ldout(store->ctx(), 0) << "ERROR: decode policy failed" << err << dendl;
3690 return -EIO;
3691 }
3692
3693 //Get the ACL from the policy
3694 RGWAccessControlList& acl = policy.get_acl();
3695
3696 //Remove grant that is set to old owner
3697 acl.remove_canon_user_grant(owner.get_id());
3698
3699 //Create a grant and add grant
3700 ACLGrant grant;
3701 grant.set_canon(user_id, display_name, RGW_PERM_FULL_CONTROL);
3702 acl.add_grant(&grant);
3703
3704 //Update the ACL owner to the new user
3705 owner.set_id(user_id);
3706 owner.set_name(display_name);
3707 policy.set_owner(owner);
3708
3709 bl.clear();
3710 encode(policy, bl);
3711
3712 obj_ctx.set_atomic(r_obj);
3713 ret = store->getRados()->set_attr(&obj_ctx, bucket_info, r_obj, RGW_ATTR_ACL, bl);
3714 if (ret < 0) {
3715 ldout(store->ctx(), 0) << "ERROR: modify attr failed " << cpp_strerror(-ret) << dendl;
3716 return ret;
3717 }
3718 }
3719 }
3720 cerr << count << " objects processed in " << bucket_info.bucket.name
3721 << ". Next marker " << list_op.params.marker.name << std::endl;
3722 } while(is_truncated);
3723 return 0;
11fdf7f2
TL
3724}
3725
9f95a23c
TL
3726int RGWBucketCtl::read_bucket_stats(const rgw_bucket& bucket,
3727 RGWBucketEnt *result,
3728 optional_yield y)
3729{
3730 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
3731 return svc.bucket->read_bucket_stats(ctx, bucket, result, y);
3732 });
3733}
3734
3735int RGWBucketCtl::read_buckets_stats(map<string, RGWBucketEnt>& m,
3736 optional_yield y)
3737{
3738 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
3739 return svc.bucket->read_buckets_stats(ctx, m, y);
3740 });
3741}
3742
3743int RGWBucketCtl::sync_user_stats(const rgw_user& user_id,
3744 const RGWBucketInfo& bucket_info,
3745 RGWBucketEnt* pent)
3746{
3747 RGWBucketEnt ent;
3748 if (!pent) {
3749 pent = &ent;
3750 }
3751 int r = svc.bi->read_stats(bucket_info, pent, null_yield);
3752 if (r < 0) {
3753 ldout(cct, 20) << __func__ << "(): failed to read bucket stats (r=" << r << ")" << dendl;
3754 return r;
3755 }
3756
3757 return ctl.user->flush_bucket_stats(user_id, *pent);
11fdf7f2
TL
3758}
3759
9f95a23c
TL
3760int RGWBucketCtl::get_sync_policy_handler(std::optional<rgw_zone_id> zone,
3761 std::optional<rgw_bucket> bucket,
3762 RGWBucketSyncPolicyHandlerRef *phandler,
3763 optional_yield y)
3764{
3765 int r = call([&](RGWSI_Bucket_X_Ctx& ctx) {
3766 return svc.bucket_sync->get_policy_handler(ctx, zone, bucket, phandler, y);
3767 });
3768 if (r < 0) {
3769 ldout(cct, 20) << __func__ << "(): failed to get policy handler for bucket=" << bucket << " (r=" << r << ")" << dendl;
3770 return r;
3771 }
3772 return 0;
11fdf7f2
TL
3773}
3774
9f95a23c
TL
3775int RGWBucketCtl::bucket_exports_data(const rgw_bucket& bucket,
3776 optional_yield y)
3777{
3778
3779 RGWBucketSyncPolicyHandlerRef handler;
3780
3781 int r = get_sync_policy_handler(std::nullopt, bucket, &handler, y);
3782 if (r < 0) {
3783 return r;
3784 }
3785
3786 return handler->bucket_exports_data();
11fdf7f2
TL
3787}
3788
9f95a23c
TL
3789int RGWBucketCtl::bucket_imports_data(const rgw_bucket& bucket,
3790 optional_yield y)
7c673cae 3791{
9f95a23c
TL
3792
3793 RGWBucketSyncPolicyHandlerRef handler;
3794
3795 int r = get_sync_policy_handler(std::nullopt, bucket, &handler, y);
3796 if (r < 0) {
3797 return r;
11fdf7f2 3798 }
9f95a23c
TL
3799
3800 return handler->bucket_imports_data();
7c673cae 3801}
9f95a23c
TL
3802
3803RGWBucketMetadataHandlerBase *RGWBucketMetaHandlerAllocator::alloc()
3804{
3805 return new RGWBucketMetadataHandler();
3806}
3807
3808RGWBucketInstanceMetadataHandlerBase *RGWBucketInstanceMetaHandlerAllocator::alloc()
3809{
3810 return new RGWBucketInstanceMetadataHandler();
3811}
3812
3813RGWBucketMetadataHandlerBase *RGWArchiveBucketMetaHandlerAllocator::alloc()
3814{
3815 return new RGWArchiveBucketMetadataHandler();
3816}
3817
3818RGWBucketInstanceMetadataHandlerBase *RGWArchiveBucketInstanceMetaHandlerAllocator::alloc()
3819{
3820 return new RGWArchiveBucketInstanceMetadataHandler();
3821}
3822