]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/ceph_objectstore_tool.cc
208db5351f5792fbd81163cccfc0c46031e40822
[ceph.git] / ceph / src / tools / ceph_objectstore_tool.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2013 Inktank
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <boost/program_options/variables_map.hpp>
16 #include <boost/program_options/parsers.hpp>
17 #include <boost/scoped_ptr.hpp>
18 #include <boost/optional.hpp>
19
20 #include <stdlib.h>
21
22 #include "common/Formatter.h"
23 #include "common/errno.h"
24 #include "common/ceph_argparse.h"
25
26 #include "global/global_init.h"
27
28 #include "os/ObjectStore.h"
29 #include "os/filestore/FileJournal.h"
30 #include "os/filestore/FileStore.h"
31 #ifdef HAVE_LIBFUSE
32 #include "os/FuseStore.h"
33 #endif
34
35 #include "osd/PGLog.h"
36 #include "osd/OSD.h"
37 #include "osd/PG.h"
38 #include "osd/ECUtil.h"
39
40 #include "json_spirit/json_spirit_value.h"
41 #include "json_spirit/json_spirit_reader.h"
42
43 #include "rebuild_mondb.h"
44 #include "ceph_objectstore_tool.h"
45 #include "include/compat.h"
46 #include "include/util.h"
47
48 namespace po = boost::program_options;
49 using namespace std;
50
51 #ifdef INTERNAL_TEST
52 CompatSet get_test_compat_set() {
53 CompatSet::FeatureSet ceph_osd_feature_compat;
54 CompatSet::FeatureSet ceph_osd_feature_ro_compat;
55 CompatSet::FeatureSet ceph_osd_feature_incompat;
56 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BASE);
57 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_PGINFO);
58 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_OLOC);
59 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEC);
60 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_CATEGORIES);
61 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_HOBJECTPOOL);
62 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BIGINFO);
63 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEVELDBINFO);
64 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEVELDBLOG);
65 #ifdef INTERNAL_TEST2
66 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SNAPMAPPER);
67 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SHARDS);
68 #endif
69 return CompatSet(ceph_osd_feature_compat, ceph_osd_feature_ro_compat,
70 ceph_osd_feature_incompat);
71 }
72 #endif
73
74 const ssize_t max_read = 1024 * 1024;
75 const int fd_none = INT_MIN;
76 bool outistty;
77 bool dry_run;
78
79 struct action_on_object_t {
80 virtual ~action_on_object_t() {}
81 virtual int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) = 0;
82 };
83
84 int _action_on_all_objects_in_pg(ObjectStore *store, coll_t coll, action_on_object_t &action, bool debug)
85 {
86 unsigned LIST_AT_A_TIME = 100;
87 ghobject_t next;
88 while (!next.is_max()) {
89 vector<ghobject_t> list;
90 int r = store->collection_list(
91 coll,
92 next,
93 ghobject_t::get_max(),
94 LIST_AT_A_TIME,
95 &list,
96 &next);
97 if (r < 0) {
98 cerr << "Error listing collection: " << coll << ", "
99 << cpp_strerror(r) << std::endl;
100 return r;
101 }
102 for (vector<ghobject_t>::iterator obj = list.begin();
103 obj != list.end();
104 ++obj) {
105 if (obj->is_pgmeta())
106 continue;
107 object_info_t oi;
108 if (coll != coll_t::meta()) {
109 bufferlist attr;
110 r = store->getattr(coll, *obj, OI_ATTR, attr);
111 if (r < 0) {
112 cerr << "Error getting attr on : " << make_pair(coll, *obj) << ", "
113 << cpp_strerror(r) << std::endl;
114 continue;
115 }
116 bufferlist::iterator bp = attr.begin();
117 try {
118 ::decode(oi, bp);
119 } catch (...) {
120 r = -EINVAL;
121 cerr << "Error getting attr on : " << make_pair(coll, *obj) << ", "
122 << cpp_strerror(r) << std::endl;
123 continue;
124 }
125 }
126 r = action.call(store, coll, *obj, oi);
127 if (r < 0)
128 return r;
129 }
130 }
131 return 0;
132 }
133
134 int action_on_all_objects_in_pg(ObjectStore *store, string pgidstr, action_on_object_t &action, bool debug)
135 {
136 spg_t pgid;
137 // Scan collections in case this is an ec pool but no shard specified
138 unsigned scanned = 0;
139 int r = 0;
140 vector<coll_t> colls_to_check;
141 vector<coll_t> candidates;
142 r = store->list_collections(candidates);
143 if (r < 0) {
144 cerr << "Error listing collections: " << cpp_strerror(r) << std::endl;
145 return r;
146 }
147 pgid.parse(pgidstr.c_str());
148 for (vector<coll_t>::iterator i = candidates.begin();
149 i != candidates.end();
150 ++i) {
151 spg_t cand_pgid;
152 if (!i->is_pg(&cand_pgid))
153 continue;
154
155 // If an exact match or treat no shard as any shard
156 if (cand_pgid == pgid ||
157 (pgid.is_no_shard() && pgid.pgid == cand_pgid.pgid)) {
158 colls_to_check.push_back(*i);
159 }
160 }
161
162 if (debug)
163 cerr << colls_to_check.size() << " pgs to scan" << std::endl;
164 for (vector<coll_t>::iterator i = colls_to_check.begin();
165 i != colls_to_check.end();
166 ++i, ++scanned) {
167 if (debug)
168 cerr << "Scanning " << *i << ", " << scanned << "/"
169 << colls_to_check.size() << " completed" << std::endl;
170 r = _action_on_all_objects_in_pg(store, *i, action, debug);
171 if (r < 0)
172 break;
173 }
174 return r;
175 }
176
177 int action_on_all_objects_in_exact_pg(ObjectStore *store, coll_t coll, action_on_object_t &action, bool debug)
178 {
179 int r = _action_on_all_objects_in_pg(store, coll, action, debug);
180 return r;
181 }
182
183 int _action_on_all_objects(ObjectStore *store, action_on_object_t &action, bool debug)
184 {
185 unsigned scanned = 0;
186 int r = 0;
187 vector<coll_t> colls_to_check;
188 vector<coll_t> candidates;
189 r = store->list_collections(candidates);
190 if (r < 0) {
191 cerr << "Error listing collections: " << cpp_strerror(r) << std::endl;
192 return r;
193 }
194 for (vector<coll_t>::iterator i = candidates.begin();
195 i != candidates.end();
196 ++i) {
197 if (i->is_pg()) {
198 colls_to_check.push_back(*i);
199 }
200 }
201
202 if (debug)
203 cerr << colls_to_check.size() << " pgs to scan" << std::endl;
204 for (vector<coll_t>::iterator i = colls_to_check.begin();
205 i != colls_to_check.end();
206 ++i, ++scanned) {
207 if (debug)
208 cerr << "Scanning " << *i << ", " << scanned << "/"
209 << colls_to_check.size() << " completed" << std::endl;
210 r = _action_on_all_objects_in_pg(store, *i, action, debug);
211 if (r < 0)
212 return r;
213 }
214 return 0;
215 }
216
217 int action_on_all_objects(ObjectStore *store, action_on_object_t &action, bool debug)
218 {
219 int r = _action_on_all_objects(store, action, debug);
220 return r;
221 }
222
223 struct pgid_object_list {
224 list<pair<coll_t, ghobject_t> > _objects;
225
226 void insert(coll_t coll, ghobject_t &ghobj) {
227 _objects.push_back(make_pair(coll, ghobj));
228 }
229
230 void dump(Formatter *f, bool human_readable) const {
231 if (!human_readable)
232 f->open_array_section("pgid_objects");
233 for (list<pair<coll_t, ghobject_t> >::const_iterator i = _objects.begin();
234 i != _objects.end();
235 ++i) {
236 f->open_array_section("pgid_object");
237 spg_t pgid;
238 bool is_pg = i->first.is_pg(&pgid);
239 if (is_pg)
240 f->dump_string("pgid", stringify(pgid));
241 if (!is_pg || !human_readable)
242 f->dump_string("coll", i->first.to_str());
243 f->open_object_section("ghobject");
244 i->second.dump(f);
245 f->close_section();
246 f->close_section();
247 if (human_readable) {
248 f->flush(cout);
249 cout << std::endl;
250 }
251 }
252 if (!human_readable) {
253 f->close_section();
254 f->flush(cout);
255 cout << std::endl;
256 }
257 }
258 };
259
260 struct lookup_ghobject : public action_on_object_t {
261 pgid_object_list _objects;
262 const string _name;
263 const boost::optional<std::string> _namespace;
264 bool _need_snapset;
265
266 lookup_ghobject(const string& name, const boost::optional<std::string>& nspace, bool need_snapset = false) : _name(name),
267 _namespace(nspace), _need_snapset(need_snapset) { }
268
269 int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) override {
270 if (_need_snapset && !ghobj.hobj.has_snapset())
271 return 0;
272 if ((_name.length() == 0 || ghobj.hobj.oid.name == _name) &&
273 (!_namespace || ghobj.hobj.nspace == _namespace))
274 _objects.insert(coll, ghobj);
275 return 0;
276 }
277
278 int size() const {
279 return _objects._objects.size();
280 }
281
282 pair<coll_t, ghobject_t> pop() {
283 pair<coll_t, ghobject_t> front = _objects._objects.front();
284 _objects._objects.pop_front();
285 return front;
286 }
287
288 void dump(Formatter *f, bool human_readable) const {
289 _objects.dump(f, human_readable);
290 }
291 };
292
293 ghobject_t infos_oid = OSD::make_infos_oid();
294 ghobject_t log_oid;
295 ghobject_t biginfo_oid;
296
297 int file_fd = fd_none;
298 bool debug;
299 super_header sh;
300
301 static int get_fd_data(int fd, bufferlist &bl)
302 {
303 uint64_t total = 0;
304 do {
305 ssize_t bytes = bl.read_fd(fd, max_read);
306 if (bytes < 0) {
307 cerr << "read_fd error " << cpp_strerror(bytes) << std::endl;
308 return bytes;
309 }
310
311 if (bytes == 0)
312 break;
313
314 total += bytes;
315 } while(true);
316
317 assert(bl.length() == total);
318 return 0;
319 }
320
321 int get_log(ObjectStore *fs, __u8 struct_ver,
322 coll_t coll, spg_t pgid, const pg_info_t &info,
323 PGLog::IndexedLog &log, pg_missing_t &missing)
324 {
325 try {
326 ostringstream oss;
327 assert(struct_ver > 0);
328 PGLog::read_log_and_missing(fs, coll,
329 struct_ver >= 8 ? coll : coll_t::meta(),
330 struct_ver >= 8 ? pgid.make_pgmeta_oid() : log_oid,
331 info, log, missing,
332 struct_ver < 9,
333 oss,
334 g_ceph_context->_conf->osd_ignore_stale_divergent_priors);
335 if (debug && oss.str().size())
336 cerr << oss.str() << std::endl;
337 }
338 catch (const buffer::error &e) {
339 cerr << "read_log_and_missing threw exception error " << e.what() << std::endl;
340 return -EFAULT;
341 }
342 return 0;
343 }
344
345 void dump_log(Formatter *formatter, ostream &out, pg_log_t &log,
346 pg_missing_t &missing)
347 {
348 formatter->open_object_section("op_log");
349 formatter->open_object_section("pg_log_t");
350 log.dump(formatter);
351 formatter->close_section();
352 formatter->flush(out);
353 formatter->open_object_section("pg_missing_t");
354 missing.dump(formatter);
355 formatter->close_section();
356 formatter->close_section();
357 formatter->flush(out);
358 }
359
360 //Based on part of OSD::load_pgs()
361 int finish_remove_pgs(ObjectStore *store)
362 {
363 vector<coll_t> ls;
364 int r = store->list_collections(ls);
365 if (r < 0) {
366 cerr << "finish_remove_pgs: failed to list pgs: " << cpp_strerror(r)
367 << std::endl;
368 return r;
369 }
370
371 for (vector<coll_t>::iterator it = ls.begin();
372 it != ls.end();
373 ++it) {
374 spg_t pgid;
375
376 if (it->is_temp(&pgid) ||
377 (it->is_pg(&pgid) && PG::_has_removal_flag(store, pgid))) {
378 cout << "finish_remove_pgs " << *it << " removing " << pgid << std::endl;
379 OSD::recursive_remove_collection(g_ceph_context, store, pgid, *it);
380 continue;
381 }
382
383 //cout << "finish_remove_pgs ignoring unrecognized " << *it << std::endl;
384 }
385 return 0;
386 }
387
388 #pragma GCC diagnostic ignored "-Wpragmas"
389 #pragma GCC diagnostic push
390 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
391
392 int mark_pg_for_removal(ObjectStore *fs, spg_t pgid, ObjectStore::Transaction *t)
393 {
394 pg_info_t info(pgid);
395 coll_t coll(pgid);
396 ghobject_t pgmeta_oid(info.pgid.make_pgmeta_oid());
397
398 bufferlist bl;
399 epoch_t map_epoch = 0;
400 int r = PG::peek_map_epoch(fs, pgid, &map_epoch, &bl);
401 if (r < 0)
402 cerr << __func__ << " warning: peek_map_epoch reported error" << std::endl;
403 PastIntervals past_intervals;
404 __u8 struct_v;
405 r = PG::read_info(fs, pgid, coll, bl, info, past_intervals, struct_v);
406 if (r < 0) {
407 cerr << __func__ << " error on read_info " << cpp_strerror(r) << std::endl;
408 return r;
409 }
410 assert(struct_v >= 8);
411 // new omap key
412 cout << "setting '_remove' omap key" << std::endl;
413 map<string,bufferlist> values;
414 ::encode((char)1, values["_remove"]);
415 t->omap_setkeys(coll, pgmeta_oid, values);
416 return 0;
417 }
418
419 #pragma GCC diagnostic pop
420 #pragma GCC diagnostic warning "-Wpragmas"
421
422 int initiate_new_remove_pg(ObjectStore *store, spg_t r_pgid,
423 ObjectStore::Sequencer &osr)
424 {
425 if (!dry_run)
426 finish_remove_pgs(store);
427 if (!store->collection_exists(coll_t(r_pgid)))
428 return -ENOENT;
429
430 cout << " marking collection for removal" << std::endl;
431 if (dry_run)
432 return 0;
433 ObjectStore::Transaction rmt;
434 int r = mark_pg_for_removal(store, r_pgid, &rmt);
435 if (r < 0) {
436 return r;
437 }
438 store->apply_transaction(&osr, std::move(rmt));
439 finish_remove_pgs(store);
440 return r;
441 }
442
443 int write_info(ObjectStore::Transaction &t, epoch_t epoch, pg_info_t &info,
444 PastIntervals &past_intervals)
445 {
446 //Empty for this
447 coll_t coll(info.pgid);
448 ghobject_t pgmeta_oid(info.pgid.make_pgmeta_oid());
449 map<string,bufferlist> km;
450 pg_info_t last_written_info;
451 int ret = PG::_prepare_write_info(
452 g_ceph_context,
453 &km, epoch,
454 info,
455 last_written_info,
456 past_intervals,
457 true, true, false);
458 if (ret) cerr << "Failed to write info" << std::endl;
459 t.omap_setkeys(coll, pgmeta_oid, km);
460 return ret;
461 }
462
463 typedef map<eversion_t, hobject_t> divergent_priors_t;
464
465 int write_pg(ObjectStore::Transaction &t, epoch_t epoch, pg_info_t &info,
466 pg_log_t &log, PastIntervals &past_intervals,
467 divergent_priors_t &divergent,
468 pg_missing_t &missing)
469 {
470 int ret = write_info(t, epoch, info, past_intervals);
471 if (ret)
472 return ret;
473 coll_t coll(info.pgid);
474 map<string,bufferlist> km;
475
476 if (!divergent.empty()) {
477 assert(missing.get_items().empty());
478 PGLog::write_log_and_missing_wo_missing(
479 t, &km, log, coll, info.pgid.make_pgmeta_oid(), divergent, true);
480 } else {
481 pg_missing_tracker_t tmissing(missing);
482 bool rebuilt_missing_set_with_deletes = missing.may_include_deletes;
483 PGLog::write_log_and_missing(
484 t, &km, log, coll, info.pgid.make_pgmeta_oid(), tmissing, true,
485 &rebuilt_missing_set_with_deletes);
486 }
487 t.omap_setkeys(coll, info.pgid.make_pgmeta_oid(), km);
488 return 0;
489 }
490
491 int do_trim_pg_log(ObjectStore *store, const coll_t &coll,
492 pg_info_t &info, const spg_t &pgid,
493 ObjectStore::Sequencer &osr, epoch_t map_epoch,
494 PastIntervals &past_intervals)
495 {
496 ghobject_t oid = pgid.make_pgmeta_oid();
497 struct stat st;
498 int r = store->stat(coll, oid, &st);
499 assert(r == 0);
500 assert(st.st_size == 0);
501
502 cerr << "Log bounds are: " << "(" << info.log_tail << ","
503 << info.last_update << "]" << std::endl;
504
505 uint64_t max_entries = g_ceph_context->_conf->osd_max_pg_log_entries;
506 if (info.last_update.version - info.log_tail.version <= max_entries) {
507 cerr << "Log not larger than osd_max_pg_log_entries " << max_entries << std::endl;
508 return 0;
509 }
510
511 assert(info.last_update.version > max_entries);
512 version_t trim_to = info.last_update.version - max_entries;
513 size_t trim_at_once = g_ceph_context->_conf->osd_pg_log_trim_max;
514 eversion_t new_tail;
515 bool done = false;
516
517 while (!done) {
518 // gather keys so we can delete them in a batch without
519 // affecting the iterator
520 set<string> keys_to_trim;
521 {
522 ObjectMap::ObjectMapIterator p = store->get_omap_iterator(coll, oid);
523 if (!p)
524 break;
525 for (p->seek_to_first(); p->valid(); p->next(false)) {
526 if (p->key()[0] == '_')
527 continue;
528 if (p->key() == "can_rollback_to")
529 continue;
530 if (p->key() == "divergent_priors")
531 continue;
532 if (p->key() == "rollback_info_trimmed_to")
533 continue;
534 if (p->key() == "may_include_deletes_in_missing")
535 continue;
536 if (p->key().substr(0, 7) == string("missing"))
537 continue;
538 if (p->key().substr(0, 4) == string("dup_"))
539 continue;
540
541 bufferlist bl = p->value();
542 bufferlist::iterator bp = bl.begin();
543 pg_log_entry_t e;
544 try {
545 e.decode_with_checksum(bp);
546 } catch (const buffer::error &e) {
547 cerr << "Error reading pg log entry: " << e << std::endl;
548 }
549 if (debug) {
550 cerr << "read entry " << e << std::endl;
551 }
552 if (e.version.version > trim_to) {
553 done = true;
554 break;
555 }
556 keys_to_trim.insert(p->key());
557 new_tail = e.version;
558 if (keys_to_trim.size() >= trim_at_once)
559 break;
560 }
561
562 if (!p->valid())
563 done = true;
564 } // deconstruct ObjectMapIterator
565
566 // delete the keys
567 if (!dry_run && !keys_to_trim.empty()) {
568 cout << "Removing keys " << *keys_to_trim.begin() << " - " << *keys_to_trim.rbegin() << std::endl;
569 ObjectStore::Transaction t;
570 t.omap_rmkeys(coll, oid, keys_to_trim);
571 int r = store->apply_transaction(&osr, std::move(t));
572 if (r) {
573 cerr << "Error trimming logs " << cpp_strerror(r) << std::endl;
574 }
575 }
576 }
577
578 // update pg info with new tail
579 if (!dry_run && new_tail != eversion_t()) {
580 info.log_tail = new_tail;
581 ObjectStore::Transaction t;
582 int ret = write_info(t, map_epoch, info, past_intervals);
583 if (ret)
584 return ret;
585 ret = store->apply_transaction(&osr, std::move(t));
586 if (ret) {
587 cerr << "Error updating pg info " << cpp_strerror(ret) << std::endl;
588 }
589 }
590
591 // compact the db since we just removed a bunch of data
592 cerr << "Finished trimming, now compacting..." << std::endl;
593 if (!dry_run)
594 store->compact();
595 return 0;
596 }
597
598 const int OMAP_BATCH_SIZE = 25;
599 void get_omap_batch(ObjectMap::ObjectMapIterator &iter, map<string, bufferlist> &oset)
600 {
601 oset.clear();
602 for (int count = OMAP_BATCH_SIZE; count && iter->valid(); --count, iter->next()) {
603 oset.insert(pair<string, bufferlist>(iter->key(), iter->value()));
604 }
605 }
606
607 int ObjectStoreTool::export_file(ObjectStore *store, coll_t cid, ghobject_t &obj)
608 {
609 struct stat st;
610 mysize_t total;
611 footer ft;
612
613 int ret = store->stat(cid, obj, &st);
614 if (ret < 0)
615 return ret;
616
617 cerr << "Read " << obj << std::endl;
618
619 total = st.st_size;
620 if (debug)
621 cerr << "size=" << total << std::endl;
622
623 object_begin objb(obj);
624
625 {
626 bufferptr bp;
627 bufferlist bl;
628 ret = store->getattr(cid, obj, OI_ATTR, bp);
629 if (ret < 0) {
630 cerr << "getattr failure object_info " << ret << std::endl;
631 return ret;
632 }
633 bl.push_back(bp);
634 decode(objb.oi, bl);
635 if (debug)
636 cerr << "object_info: " << objb.oi << std::endl;
637 }
638
639 // NOTE: we include whiteouts, lost, etc.
640
641 ret = write_section(TYPE_OBJECT_BEGIN, objb, file_fd);
642 if (ret < 0)
643 return ret;
644
645 uint64_t offset = 0;
646 bufferlist rawdatabl;
647 while(total > 0) {
648 rawdatabl.clear();
649 mysize_t len = max_read;
650 if (len > total)
651 len = total;
652
653 ret = store->read(cid, obj, offset, len, rawdatabl);
654 if (ret < 0)
655 return ret;
656 if (ret == 0)
657 return -EINVAL;
658
659 data_section dblock(offset, len, rawdatabl);
660 if (debug)
661 cerr << "data section offset=" << offset << " len=" << len << std::endl;
662
663 total -= ret;
664 offset += ret;
665
666 ret = write_section(TYPE_DATA, dblock, file_fd);
667 if (ret) return ret;
668 }
669
670 //Handle attrs for this object
671 map<string,bufferptr> aset;
672 ret = store->getattrs(cid, obj, aset);
673 if (ret) return ret;
674 attr_section as(aset);
675 ret = write_section(TYPE_ATTRS, as, file_fd);
676 if (ret)
677 return ret;
678
679 if (debug) {
680 cerr << "attrs size " << aset.size() << std::endl;
681 }
682
683 //Handle omap information
684 bufferlist hdrbuf;
685 ret = store->omap_get_header(cid, obj, &hdrbuf, true);
686 if (ret < 0) {
687 cerr << "omap_get_header: " << cpp_strerror(ret) << std::endl;
688 return ret;
689 }
690
691 omap_hdr_section ohs(hdrbuf);
692 ret = write_section(TYPE_OMAP_HDR, ohs, file_fd);
693 if (ret)
694 return ret;
695
696 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(cid, obj);
697 if (!iter) {
698 ret = -ENOENT;
699 cerr << "omap_get_iterator: " << cpp_strerror(ret) << std::endl;
700 return ret;
701 }
702 iter->seek_to_first();
703 int mapcount = 0;
704 map<string, bufferlist> out;
705 while(iter->valid()) {
706 get_omap_batch(iter, out);
707
708 if (out.empty()) break;
709
710 mapcount += out.size();
711 omap_section oms(out);
712 ret = write_section(TYPE_OMAP, oms, file_fd);
713 if (ret)
714 return ret;
715 }
716 if (debug)
717 cerr << "omap map size " << mapcount << std::endl;
718
719 ret = write_simple(TYPE_OBJECT_END, file_fd);
720 if (ret)
721 return ret;
722
723 return 0;
724 }
725
726 int ObjectStoreTool::export_files(ObjectStore *store, coll_t coll)
727 {
728 ghobject_t next;
729
730 while (!next.is_max()) {
731 vector<ghobject_t> objects;
732 int r = store->collection_list(coll, next, ghobject_t::get_max(), 300,
733 &objects, &next);
734 if (r < 0)
735 return r;
736 for (vector<ghobject_t>::iterator i = objects.begin();
737 i != objects.end();
738 ++i) {
739 assert(!i->hobj.is_meta());
740 if (i->is_pgmeta() || i->hobj.is_temp()) {
741 continue;
742 }
743 r = export_file(store, coll, *i);
744 if (r < 0)
745 return r;
746 }
747 }
748 return 0;
749 }
750
751 int set_inc_osdmap(ObjectStore *store, epoch_t e, bufferlist& bl, bool force,
752 ObjectStore::Sequencer &osr) {
753 OSDMap::Incremental inc;
754 bufferlist::iterator it = bl.begin();
755 inc.decode(it);
756 if (e == 0) {
757 e = inc.epoch;
758 } else if (e != inc.epoch) {
759 cerr << "incremental.epoch mismatch: "
760 << inc.epoch << " != " << e << std::endl;
761 if (force) {
762 cerr << "But will continue anyway." << std::endl;
763 } else {
764 return -EINVAL;
765 }
766 }
767 const ghobject_t inc_oid = OSD::get_inc_osdmap_pobject_name(e);
768 if (!store->exists(coll_t::meta(), inc_oid)) {
769 cerr << "inc-osdmap (" << inc_oid << ") does not exist." << std::endl;
770 if (!force) {
771 return -ENOENT;
772 }
773 cout << "Creating a new epoch." << std::endl;
774 }
775 if (dry_run)
776 return 0;
777 ObjectStore::Transaction t;
778 t.write(coll_t::meta(), inc_oid, 0, bl.length(), bl);
779 t.truncate(coll_t::meta(), inc_oid, bl.length());
780 int ret = store->apply_transaction(&osr, std::move(t));
781 if (ret) {
782 cerr << "Failed to set inc-osdmap (" << inc_oid << "): " << ret << std::endl;
783 } else {
784 cout << "Wrote inc-osdmap." << inc.epoch << std::endl;
785 }
786 return ret;
787 }
788
789 int get_inc_osdmap(ObjectStore *store, epoch_t e, bufferlist& bl)
790 {
791 if (store->read(coll_t::meta(),
792 OSD::get_inc_osdmap_pobject_name(e),
793 0, 0, bl) < 0) {
794 return -ENOENT;
795 }
796 return 0;
797 }
798
799 int set_osdmap(ObjectStore *store, epoch_t e, bufferlist& bl, bool force,
800 ObjectStore::Sequencer &osr) {
801 OSDMap osdmap;
802 osdmap.decode(bl);
803 if (e == 0) {
804 e = osdmap.get_epoch();
805 } else if (e != osdmap.get_epoch()) {
806 cerr << "osdmap.epoch mismatch: "
807 << e << " != " << osdmap.get_epoch() << std::endl;
808 if (force) {
809 cerr << "But will continue anyway." << std::endl;
810 } else {
811 return -EINVAL;
812 }
813 }
814 const ghobject_t full_oid = OSD::get_osdmap_pobject_name(e);
815 if (!store->exists(coll_t::meta(), full_oid)) {
816 cerr << "osdmap (" << full_oid << ") does not exist." << std::endl;
817 if (!force) {
818 return -ENOENT;
819 }
820 cout << "Creating a new epoch." << std::endl;
821 }
822 if (dry_run)
823 return 0;
824 ObjectStore::Transaction t;
825 t.write(coll_t::meta(), full_oid, 0, bl.length(), bl);
826 t.truncate(coll_t::meta(), full_oid, bl.length());
827 int ret = store->apply_transaction(&osr, std::move(t));
828 if (ret) {
829 cerr << "Failed to set osdmap (" << full_oid << "): " << ret << std::endl;
830 } else {
831 cout << "Wrote osdmap." << osdmap.get_epoch() << std::endl;
832 }
833 return ret;
834 }
835
836 int get_osdmap(ObjectStore *store, epoch_t e, OSDMap &osdmap, bufferlist& bl)
837 {
838 bool found = store->read(
839 coll_t::meta(), OSD::get_osdmap_pobject_name(e), 0, 0, bl) >= 0;
840 if (!found) {
841 cerr << "Can't find OSDMap for pg epoch " << e << std::endl;
842 return -ENOENT;
843 }
844 osdmap.decode(bl);
845 if (debug)
846 cerr << osdmap << std::endl;
847 return 0;
848 }
849
850 int add_osdmap(ObjectStore *store, metadata_section &ms)
851 {
852 return get_osdmap(store, ms.map_epoch, ms.osdmap, ms.osdmap_bl);
853 }
854
855 int ObjectStoreTool::do_export(ObjectStore *fs, coll_t coll, spg_t pgid,
856 pg_info_t &info, epoch_t map_epoch, __u8 struct_ver,
857 const OSDSuperblock& superblock,
858 PastIntervals &past_intervals)
859 {
860 PGLog::IndexedLog log;
861 pg_missing_t missing;
862
863 cerr << "Exporting " << pgid << std::endl;
864
865 int ret = get_log(fs, struct_ver, coll, pgid, info, log, missing);
866 if (ret > 0)
867 return ret;
868
869 if (debug) {
870 Formatter *formatter = Formatter::create("json-pretty");
871 assert(formatter);
872 dump_log(formatter, cerr, log, missing);
873 delete formatter;
874 }
875 write_super();
876
877 pg_begin pgb(pgid, superblock);
878 // Special case: If replicated pg don't require the importing OSD to have shard feature
879 if (pgid.is_no_shard()) {
880 pgb.superblock.compat_features.incompat.remove(CEPH_OSD_FEATURE_INCOMPAT_SHARDS);
881 }
882 ret = write_section(TYPE_PG_BEGIN, pgb, file_fd);
883 if (ret)
884 return ret;
885
886 // The metadata_section is now before files, so import can detect
887 // errors and abort without wasting time.
888 metadata_section ms(
889 struct_ver,
890 map_epoch,
891 info,
892 log,
893 past_intervals,
894 missing);
895 ret = add_osdmap(fs, ms);
896 if (ret)
897 return ret;
898 ret = write_section(TYPE_PG_METADATA, ms, file_fd);
899 if (ret)
900 return ret;
901
902 ret = export_files(fs, coll);
903 if (ret) {
904 cerr << "export_files error " << ret << std::endl;
905 return ret;
906 }
907
908 ret = write_simple(TYPE_PG_END, file_fd);
909 if (ret)
910 return ret;
911
912 return 0;
913 }
914
915 int dump_data(Formatter *formatter, bufferlist &bl)
916 {
917 bufferlist::iterator ebliter = bl.begin();
918 data_section ds;
919 ds.decode(ebliter);
920
921 formatter->open_object_section("data_block");
922 formatter->dump_unsigned("offset", ds.offset);
923 formatter->dump_unsigned("len", ds.len);
924 // XXX: Add option to dump data like od -cx ?
925 formatter->close_section();
926 formatter->flush(cout);
927 return 0;
928 }
929
930 int get_data(ObjectStore *store, coll_t coll, ghobject_t hoid,
931 ObjectStore::Transaction *t, bufferlist &bl)
932 {
933 bufferlist::iterator ebliter = bl.begin();
934 data_section ds;
935 ds.decode(ebliter);
936
937 if (debug)
938 cerr << "\tdata: offset " << ds.offset << " len " << ds.len << std::endl;
939 t->write(coll, hoid, ds.offset, ds.len, ds.databl);
940 return 0;
941 }
942
943 int dump_attrs(
944 Formatter *formatter, ghobject_t hoid,
945 bufferlist &bl)
946 {
947 bufferlist::iterator ebliter = bl.begin();
948 attr_section as;
949 as.decode(ebliter);
950
951 // This could have been handled in the caller if we didn't need to
952 // support exports that didn't include object_info_t in object_begin.
953 if (hoid.generation == ghobject_t::NO_GEN &&
954 hoid.hobj.is_head()) {
955 map<string,bufferlist>::iterator mi = as.data.find(SS_ATTR);
956 if (mi != as.data.end()) {
957 SnapSet snapset;
958 auto p = mi->second.begin();
959 snapset.decode(p);
960 formatter->open_object_section("snapset");
961 snapset.dump(formatter);
962 formatter->close_section();
963 } else {
964 formatter->open_object_section("snapset");
965 formatter->dump_string("error", "missing SS_ATTR");
966 formatter->close_section();
967 }
968 }
969
970 formatter->open_object_section("attrs");
971 formatter->open_array_section("user");
972 for (auto kv : as.data) {
973 // Skip system attributes
974 if (('_' != kv.first.at(0)) || kv.first.size() == 1)
975 continue;
976 formatter->open_object_section("user_attr");
977 formatter->dump_string("name", kv.first.substr(1));
978 bool b64;
979 formatter->dump_string("value", cleanbin(kv.second, b64));
980 formatter->dump_bool("Base64", b64);
981 formatter->close_section();
982 }
983 formatter->close_section();
984 formatter->open_array_section("system");
985 for (auto kv : as.data) {
986 // Skip user attributes
987 if (('_' == kv.first.at(0)) && kv.first.size() != 1)
988 continue;
989 formatter->open_object_section("sys_attr");
990 formatter->dump_string("name", kv.first);
991 formatter->close_section();
992 }
993 formatter->close_section();
994 formatter->close_section();
995 formatter->flush(cout);
996
997 return 0;
998 }
999
1000 int get_attrs(
1001 ObjectStore *store, coll_t coll, ghobject_t hoid,
1002 ObjectStore::Transaction *t, bufferlist &bl,
1003 OSDriver &driver, SnapMapper &snap_mapper)
1004 {
1005 bufferlist::iterator ebliter = bl.begin();
1006 attr_section as;
1007 as.decode(ebliter);
1008
1009 if (debug)
1010 cerr << "\tattrs: len " << as.data.size() << std::endl;
1011 t->setattrs(coll, hoid, as.data);
1012
1013 // This could have been handled in the caller if we didn't need to
1014 // support exports that didn't include object_info_t in object_begin.
1015 if (hoid.generation == ghobject_t::NO_GEN) {
1016 if (hoid.hobj.snap < CEPH_MAXSNAP) {
1017 map<string,bufferlist>::iterator mi = as.data.find(OI_ATTR);
1018 if (mi != as.data.end()) {
1019 object_info_t oi(mi->second);
1020
1021 if (debug)
1022 cerr << "object_info " << oi << std::endl;
1023
1024 OSDriver::OSTransaction _t(driver.get_transaction(t));
1025 set<snapid_t> oi_snaps(oi.legacy_snaps.begin(), oi.legacy_snaps.end());
1026 if (!oi_snaps.empty()) {
1027 if (debug)
1028 cerr << "\tsetting legacy snaps " << oi_snaps << std::endl;
1029 snap_mapper.add_oid(hoid.hobj, oi_snaps, &_t);
1030 }
1031 }
1032 } else {
1033 if (hoid.hobj.is_head()) {
1034 map<string,bufferlist>::iterator mi = as.data.find(SS_ATTR);
1035 if (mi != as.data.end()) {
1036 SnapSet snapset;
1037 auto p = mi->second.begin();
1038 snapset.decode(p);
1039 cout << "snapset " << snapset << std::endl;
1040 if (!snapset.is_legacy()) {
1041 for (auto& p : snapset.clone_snaps) {
1042 ghobject_t clone = hoid;
1043 clone.hobj.snap = p.first;
1044 set<snapid_t> snaps(p.second.begin(), p.second.end());
1045 if (!store->exists(coll, clone)) {
1046 // no clone, skip. this is probably a cache pool. this works
1047 // because we use a separate transaction per object and clones
1048 // come before head in the archive.
1049 if (debug)
1050 cerr << "\tskipping missing " << clone << " (snaps "
1051 << snaps << ")" << std::endl;
1052 continue;
1053 }
1054 if (debug)
1055 cerr << "\tsetting " << clone.hobj << " snaps " << snaps
1056 << std::endl;
1057 OSDriver::OSTransaction _t(driver.get_transaction(t));
1058 assert(!snaps.empty());
1059 snap_mapper.add_oid(clone.hobj, snaps, &_t);
1060 }
1061 }
1062 } else {
1063 cerr << "missing SS_ATTR on " << hoid << std::endl;
1064 }
1065 }
1066 }
1067 }
1068
1069 return 0;
1070 }
1071
1072 int dump_omap_hdr(Formatter *formatter, bufferlist &bl)
1073 {
1074 bufferlist::iterator ebliter = bl.begin();
1075 omap_hdr_section oh;
1076 oh.decode(ebliter);
1077
1078 formatter->open_object_section("omap_header");
1079 formatter->dump_string("value", string(oh.hdr.c_str(), oh.hdr.length()));
1080 formatter->close_section();
1081 formatter->flush(cout);
1082 return 0;
1083 }
1084
1085 int get_omap_hdr(ObjectStore *store, coll_t coll, ghobject_t hoid,
1086 ObjectStore::Transaction *t, bufferlist &bl)
1087 {
1088 bufferlist::iterator ebliter = bl.begin();
1089 omap_hdr_section oh;
1090 oh.decode(ebliter);
1091
1092 if (debug)
1093 cerr << "\tomap header: " << string(oh.hdr.c_str(), oh.hdr.length())
1094 << std::endl;
1095 t->omap_setheader(coll, hoid, oh.hdr);
1096 return 0;
1097 }
1098
1099 int dump_omap(Formatter *formatter, bufferlist &bl)
1100 {
1101 bufferlist::iterator ebliter = bl.begin();
1102 omap_section os;
1103 os.decode(ebliter);
1104
1105 formatter->open_object_section("omaps");
1106 formatter->dump_unsigned("count", os.omap.size());
1107 formatter->open_array_section("data");
1108 for (auto o : os.omap) {
1109 formatter->open_object_section("omap");
1110 formatter->dump_string("name", o.first);
1111 bool b64;
1112 formatter->dump_string("value", cleanbin(o.second, b64));
1113 formatter->dump_bool("Base64", b64);
1114 formatter->close_section();
1115 }
1116 formatter->close_section();
1117 formatter->close_section();
1118 formatter->flush(cout);
1119 return 0;
1120 }
1121
1122 int get_omap(ObjectStore *store, coll_t coll, ghobject_t hoid,
1123 ObjectStore::Transaction *t, bufferlist &bl)
1124 {
1125 bufferlist::iterator ebliter = bl.begin();
1126 omap_section os;
1127 os.decode(ebliter);
1128
1129 if (debug)
1130 cerr << "\tomap: size " << os.omap.size() << std::endl;
1131 t->omap_setkeys(coll, hoid, os.omap);
1132 return 0;
1133 }
1134
1135 int ObjectStoreTool::dump_object(Formatter *formatter,
1136 bufferlist &bl)
1137 {
1138 bufferlist::iterator ebliter = bl.begin();
1139 object_begin ob;
1140 ob.decode(ebliter);
1141
1142 if (ob.hoid.hobj.is_temp()) {
1143 cerr << "ERROR: Export contains temporary object '" << ob.hoid << "'" << std::endl;
1144 return -EFAULT;
1145 }
1146
1147 formatter->open_object_section("object");
1148 formatter->open_object_section("oid");
1149 ob.hoid.dump(formatter);
1150 formatter->close_section();
1151 formatter->open_object_section("object_info");
1152 ob.oi.dump(formatter);
1153 formatter->close_section();
1154
1155 bufferlist ebl;
1156 bool done = false;
1157 while(!done) {
1158 sectiontype_t type;
1159 int ret = read_section(&type, &ebl);
1160 if (ret)
1161 return ret;
1162
1163 //cout << "\tdo_object: Section type " << hex << type << dec << std::endl;
1164 //cout << "\t\tsection size " << ebl.length() << std::endl;
1165 if (type >= END_OF_TYPES) {
1166 cout << "Skipping unknown object section type" << std::endl;
1167 continue;
1168 }
1169 switch(type) {
1170 case TYPE_DATA:
1171 if (dry_run) break;
1172 ret = dump_data(formatter, ebl);
1173 if (ret) return ret;
1174 break;
1175 case TYPE_ATTRS:
1176 if (dry_run) break;
1177 ret = dump_attrs(formatter, ob.hoid, ebl);
1178 if (ret) return ret;
1179 break;
1180 case TYPE_OMAP_HDR:
1181 if (dry_run) break;
1182 ret = dump_omap_hdr(formatter, ebl);
1183 if (ret) return ret;
1184 break;
1185 case TYPE_OMAP:
1186 if (dry_run) break;
1187 ret = dump_omap(formatter, ebl);
1188 if (ret) return ret;
1189 break;
1190 case TYPE_OBJECT_END:
1191 done = true;
1192 break;
1193 default:
1194 cerr << "Unknown section type " << type << std::endl;
1195 return -EFAULT;
1196 }
1197 }
1198 formatter->close_section();
1199 return 0;
1200 }
1201
1202 int ObjectStoreTool::get_object(ObjectStore *store, coll_t coll,
1203 bufferlist &bl, OSDMap &curmap,
1204 bool *skipped_objects,
1205 ObjectStore::Sequencer &osr)
1206 {
1207 ObjectStore::Transaction tran;
1208 ObjectStore::Transaction *t = &tran;
1209 bufferlist::iterator ebliter = bl.begin();
1210 object_begin ob;
1211 ob.decode(ebliter);
1212 OSDriver driver(
1213 store,
1214 coll_t(),
1215 OSD::make_snapmapper_oid());
1216 spg_t pg;
1217 coll.is_pg_prefix(&pg);
1218 SnapMapper mapper(g_ceph_context, &driver, 0, 0, 0, pg.shard);
1219
1220 if (ob.hoid.hobj.is_temp()) {
1221 cerr << "ERROR: Export contains temporary object '" << ob.hoid << "'" << std::endl;
1222 return -EFAULT;
1223 }
1224 assert(g_ceph_context);
1225 if (ob.hoid.hobj.nspace != g_ceph_context->_conf->osd_hit_set_namespace) {
1226 object_t oid = ob.hoid.hobj.oid;
1227 object_locator_t loc(ob.hoid.hobj);
1228 pg_t raw_pgid = curmap.object_locator_to_pg(oid, loc);
1229 pg_t pgid = curmap.raw_pg_to_pg(raw_pgid);
1230
1231 spg_t coll_pgid;
1232 if (coll.is_pg(&coll_pgid) == false) {
1233 cerr << "INTERNAL ERROR: Bad collection during import" << std::endl;
1234 return -EFAULT;
1235 }
1236 if (coll_pgid.shard != ob.hoid.shard_id) {
1237 cerr << "INTERNAL ERROR: Importing shard " << coll_pgid.shard
1238 << " but object shard is " << ob.hoid.shard_id << std::endl;
1239 return -EFAULT;
1240 }
1241
1242 if (coll_pgid.pgid != pgid) {
1243 cerr << "Skipping object '" << ob.hoid << "' which belongs in pg " << pgid << std::endl;
1244 *skipped_objects = true;
1245 skip_object(bl);
1246 return 0;
1247 }
1248 }
1249
1250 if (!dry_run)
1251 t->touch(coll, ob.hoid);
1252
1253 cout << "Write " << ob.hoid << std::endl;
1254
1255 bufferlist ebl;
1256 bool done = false;
1257 while(!done) {
1258 sectiontype_t type;
1259 int ret = read_section(&type, &ebl);
1260 if (ret)
1261 return ret;
1262
1263 //cout << "\tdo_object: Section type " << hex << type << dec << std::endl;
1264 //cout << "\t\tsection size " << ebl.length() << std::endl;
1265 if (type >= END_OF_TYPES) {
1266 cout << "Skipping unknown object section type" << std::endl;
1267 continue;
1268 }
1269 switch(type) {
1270 case TYPE_DATA:
1271 if (dry_run) break;
1272 ret = get_data(store, coll, ob.hoid, t, ebl);
1273 if (ret) return ret;
1274 break;
1275 case TYPE_ATTRS:
1276 if (dry_run) break;
1277 ret = get_attrs(store, coll, ob.hoid, t, ebl, driver, mapper);
1278 if (ret) return ret;
1279 break;
1280 case TYPE_OMAP_HDR:
1281 if (dry_run) break;
1282 ret = get_omap_hdr(store, coll, ob.hoid, t, ebl);
1283 if (ret) return ret;
1284 break;
1285 case TYPE_OMAP:
1286 if (dry_run) break;
1287 ret = get_omap(store, coll, ob.hoid, t, ebl);
1288 if (ret) return ret;
1289 break;
1290 case TYPE_OBJECT_END:
1291 done = true;
1292 break;
1293 default:
1294 cerr << "Unknown section type " << type << std::endl;
1295 return -EFAULT;
1296 }
1297 }
1298 if (!dry_run)
1299 store->apply_transaction(&osr, std::move(*t));
1300 return 0;
1301 }
1302
1303 int dump_pg_metadata(Formatter *formatter, bufferlist &bl, metadata_section &ms)
1304 {
1305 bufferlist::iterator ebliter = bl.begin();
1306 ms.decode(ebliter);
1307
1308 formatter->open_object_section("metadata_section");
1309
1310 formatter->dump_unsigned("pg_disk_version", (int)ms.struct_ver);
1311 formatter->dump_unsigned("map_epoch", ms.map_epoch);
1312
1313 formatter->open_object_section("OSDMap");
1314 ms.osdmap.dump(formatter);
1315 formatter->close_section();
1316 formatter->flush(cout);
1317 cout << std::endl;
1318
1319 formatter->open_object_section("info");
1320 ms.info.dump(formatter);
1321 formatter->close_section();
1322 formatter->flush(cout);
1323
1324 formatter->open_object_section("log");
1325 ms.log.dump(formatter);
1326 formatter->close_section();
1327 formatter->flush(cout);
1328
1329 formatter->open_object_section("pg_missing_t");
1330 ms.missing.dump(formatter);
1331 formatter->close_section();
1332
1333 // XXX: ms.past_intervals?
1334
1335 formatter->close_section();
1336 formatter->flush(cout);
1337
1338 if (ms.osdmap.get_epoch() != 0 && ms.map_epoch != ms.osdmap.get_epoch()) {
1339 cerr << "FATAL: Invalid OSDMap epoch in export data" << std::endl;
1340 return -EFAULT;
1341 }
1342
1343 return 0;
1344 }
1345
1346 int get_pg_metadata(ObjectStore *store, bufferlist &bl, metadata_section &ms,
1347 const OSDSuperblock& sb, OSDMap& curmap, spg_t pgid)
1348 {
1349 bufferlist::iterator ebliter = bl.begin();
1350 ms.decode(ebliter);
1351 spg_t old_pgid = ms.info.pgid;
1352 ms.info.pgid = pgid;
1353
1354 #if DIAGNOSTIC
1355 Formatter *formatter = new JSONFormatter(true);
1356 cout << "export pgid " << old_pgid << std::endl;
1357 cout << "struct_v " << (int)ms.struct_ver << std::endl;
1358 cout << "map epoch " << ms.map_epoch << std::endl;
1359
1360 formatter->open_object_section("importing OSDMap");
1361 ms.osdmap.dump(formatter);
1362 formatter->close_section();
1363 formatter->flush(cout);
1364 cout << std::endl;
1365
1366 cout << "osd current epoch " << sb.current_epoch << std::endl;
1367 formatter->open_object_section("current OSDMap");
1368 curmap.dump(formatter);
1369 formatter->close_section();
1370 formatter->flush(cout);
1371 cout << std::endl;
1372
1373 formatter->open_object_section("info");
1374 ms.info.dump(formatter);
1375 formatter->close_section();
1376 formatter->flush(cout);
1377 cout << std::endl;
1378
1379 formatter->open_object_section("log");
1380 ms.log.dump(formatter);
1381 formatter->close_section();
1382 formatter->flush(cout);
1383 cout << std::endl;
1384
1385 formatter->flush(cout);
1386 cout << std::endl;
1387 #endif
1388
1389 if (ms.osdmap.get_epoch() != 0 && ms.map_epoch != ms.osdmap.get_epoch()) {
1390 cerr << "FATAL: Invalid OSDMap epoch in export data" << std::endl;
1391 return -EFAULT;
1392 }
1393
1394 if (ms.map_epoch > sb.current_epoch) {
1395 cerr << "ERROR: Export PG's map_epoch " << ms.map_epoch << " > OSD's epoch " << sb.current_epoch << std::endl;
1396 cerr << "The OSD you are using is older than the exported PG" << std::endl;
1397 cerr << "Either use another OSD or join selected OSD to cluster to update it first" << std::endl;
1398 return -EINVAL;
1399 }
1400
1401 // Pool verified to exist for call to get_pg_num().
1402 unsigned new_pg_num = curmap.get_pg_num(pgid.pgid.pool());
1403
1404 if (pgid.pgid.ps() >= new_pg_num) {
1405 cerr << "Illegal pgid, the seed is larger than current pg_num" << std::endl;
1406 return -EINVAL;
1407 }
1408
1409 // Old exports didn't include OSDMap, see if we have a copy locally
1410 if (ms.osdmap.get_epoch() == 0) {
1411 OSDMap findmap;
1412 bufferlist findmap_bl;
1413 int ret = get_osdmap(store, ms.map_epoch, findmap, findmap_bl);
1414 if (ret == 0) {
1415 ms.osdmap.deepish_copy_from(findmap);
1416 } else {
1417 cerr << "WARNING: No OSDMap in old export,"
1418 " some objects may be ignored due to a split" << std::endl;
1419 }
1420 }
1421
1422 // Make sure old_pg_num is 0 in the unusual case that OSDMap not in export
1423 // nor can we find a local copy.
1424 unsigned old_pg_num = 0;
1425 if (ms.osdmap.get_epoch() != 0)
1426 old_pg_num = ms.osdmap.get_pg_num(pgid.pgid.pool());
1427
1428 if (debug) {
1429 cerr << "old_pg_num " << old_pg_num << std::endl;
1430 cerr << "new_pg_num " << new_pg_num << std::endl;
1431 cerr << ms.osdmap << std::endl;
1432 cerr << curmap << std::endl;
1433 }
1434
1435 // If we have managed to have a good OSDMap we can do these checks
1436 if (old_pg_num) {
1437 if (old_pgid.pgid.ps() >= old_pg_num) {
1438 cerr << "FATAL: pgid invalid for original map epoch" << std::endl;
1439 return -EFAULT;
1440 }
1441 if (pgid.pgid.ps() >= old_pg_num) {
1442 cout << "NOTICE: Post split pgid specified" << std::endl;
1443 } else {
1444 spg_t parent(pgid);
1445 if (parent.is_split(old_pg_num, new_pg_num, NULL)) {
1446 cerr << "WARNING: Split occurred, some objects may be ignored" << std::endl;
1447 }
1448 }
1449 }
1450
1451 if (debug) {
1452 cerr << "Import pgid " << ms.info.pgid << std::endl;
1453 cerr << "Previous past_intervals " << ms.past_intervals << std::endl;
1454 cerr << "history.same_interval_since " << ms.info.history.same_interval_since << std::endl;
1455 }
1456
1457 // Let osd recompute past_intervals and same_interval_since
1458 ms.past_intervals.clear();
1459 ms.info.history.same_interval_since = 0;
1460
1461 if (debug)
1462 cerr << "Changing pg epoch " << ms.map_epoch << " to " << sb.current_epoch << std::endl;
1463
1464 ms.map_epoch = sb.current_epoch;
1465
1466 return 0;
1467 }
1468
1469 // out: pg_log_t that only has entries that apply to import_pgid using curmap
1470 // reject: Entries rejected from "in" are in the reject.log. Other fields not set.
1471 void filter_divergent_priors(spg_t import_pgid, const OSDMap &curmap,
1472 const string &hit_set_namespace, const divergent_priors_t &in,
1473 divergent_priors_t &out, divergent_priors_t &reject)
1474 {
1475 out.clear();
1476 reject.clear();
1477
1478 for (divergent_priors_t::const_iterator i = in.begin();
1479 i != in.end(); ++i) {
1480
1481 // Reject divergent priors for temporary objects
1482 if (i->second.is_temp()) {
1483 reject.insert(*i);
1484 continue;
1485 }
1486
1487 if (i->second.nspace != hit_set_namespace) {
1488 object_t oid = i->second.oid;
1489 object_locator_t loc(i->second);
1490 pg_t raw_pgid = curmap.object_locator_to_pg(oid, loc);
1491 pg_t pgid = curmap.raw_pg_to_pg(raw_pgid);
1492
1493 if (import_pgid.pgid == pgid) {
1494 out.insert(*i);
1495 } else {
1496 reject.insert(*i);
1497 }
1498 } else {
1499 out.insert(*i);
1500 }
1501 }
1502 }
1503
1504 int ObjectStoreTool::dump_import(Formatter *formatter)
1505 {
1506 bufferlist ebl;
1507 pg_info_t info;
1508 PGLog::IndexedLog log;
1509 //bool skipped_objects = false;
1510
1511 int ret = read_super();
1512 if (ret)
1513 return ret;
1514
1515 if (sh.magic != super_header::super_magic) {
1516 cerr << "Invalid magic number" << std::endl;
1517 return -EFAULT;
1518 }
1519
1520 if (sh.version > super_header::super_ver) {
1521 cerr << "Can't handle export format version=" << sh.version << std::endl;
1522 return -EINVAL;
1523 }
1524
1525 formatter->open_object_section("Export");
1526
1527 //First section must be TYPE_PG_BEGIN
1528 sectiontype_t type;
1529 ret = read_section(&type, &ebl);
1530 if (ret)
1531 return ret;
1532 if (type == TYPE_POOL_BEGIN) {
1533 cerr << "Dump of pool exports not supported" << std::endl;
1534 return -EINVAL;
1535 } else if (type != TYPE_PG_BEGIN) {
1536 cerr << "Invalid first section type " << std::to_string(type) << std::endl;
1537 return -EFAULT;
1538 }
1539
1540 bufferlist::iterator ebliter = ebl.begin();
1541 pg_begin pgb;
1542 pgb.decode(ebliter);
1543 spg_t pgid = pgb.pgid;
1544
1545 formatter->dump_string("pgid", stringify(pgid));
1546 formatter->dump_string("cluster_fsid", stringify(pgb.superblock.cluster_fsid));
1547 formatter->dump_string("features", stringify(pgb.superblock.compat_features));
1548
1549 bool done = false;
1550 bool found_metadata = false;
1551 metadata_section ms;
1552 bool objects_started = false;
1553 while(!done) {
1554 ret = read_section(&type, &ebl);
1555 if (ret)
1556 return ret;
1557
1558 if (debug) {
1559 cerr << "dump_import: Section type " << std::to_string(type) << std::endl;
1560 }
1561 if (type >= END_OF_TYPES) {
1562 cerr << "Skipping unknown section type" << std::endl;
1563 continue;
1564 }
1565 switch(type) {
1566 case TYPE_OBJECT_BEGIN:
1567 if (!objects_started) {
1568 formatter->open_array_section("objects");
1569 objects_started = true;
1570 }
1571 ret = dump_object(formatter, ebl);
1572 if (ret) return ret;
1573 break;
1574 case TYPE_PG_METADATA:
1575 if (objects_started)
1576 cerr << "WARNING: metadata_section out of order" << std::endl;
1577 ret = dump_pg_metadata(formatter, ebl, ms);
1578 if (ret) return ret;
1579 found_metadata = true;
1580 break;
1581 case TYPE_PG_END:
1582 if (objects_started) {
1583 formatter->close_section();
1584 }
1585 done = true;
1586 break;
1587 default:
1588 cerr << "Unknown section type " << std::to_string(type) << std::endl;
1589 return -EFAULT;
1590 }
1591 }
1592
1593 if (!found_metadata) {
1594 cerr << "Missing metadata section" << std::endl;
1595 return -EFAULT;
1596 }
1597
1598 formatter->close_section();
1599 formatter->flush(cout);
1600
1601 return 0;
1602 }
1603
1604 int ObjectStoreTool::do_import(ObjectStore *store, OSDSuperblock& sb,
1605 bool force, std::string pgidstr,
1606 ObjectStore::Sequencer &osr)
1607 {
1608 bufferlist ebl;
1609 pg_info_t info;
1610 PGLog::IndexedLog log;
1611 bool skipped_objects = false;
1612
1613 if (!dry_run)
1614 finish_remove_pgs(store);
1615
1616 int ret = read_super();
1617 if (ret)
1618 return ret;
1619
1620 if (sh.magic != super_header::super_magic) {
1621 cerr << "Invalid magic number" << std::endl;
1622 return -EFAULT;
1623 }
1624
1625 if (sh.version > super_header::super_ver) {
1626 cerr << "Can't handle export format version=" << sh.version << std::endl;
1627 return -EINVAL;
1628 }
1629
1630 //First section must be TYPE_PG_BEGIN
1631 sectiontype_t type;
1632 ret = read_section(&type, &ebl);
1633 if (ret)
1634 return ret;
1635 if (type == TYPE_POOL_BEGIN) {
1636 cerr << "Pool exports cannot be imported into a PG" << std::endl;
1637 return -EINVAL;
1638 } else if (type != TYPE_PG_BEGIN) {
1639 cerr << "Invalid first section type " << std::to_string(type) << std::endl;
1640 return -EFAULT;
1641 }
1642
1643 bufferlist::iterator ebliter = ebl.begin();
1644 pg_begin pgb;
1645 pgb.decode(ebliter);
1646 spg_t pgid = pgb.pgid;
1647 spg_t orig_pgid = pgid;
1648
1649 if (pgidstr.length()) {
1650 spg_t user_pgid;
1651
1652 bool ok = user_pgid.parse(pgidstr.c_str());
1653 // This succeeded in main() already
1654 assert(ok);
1655 if (pgid != user_pgid) {
1656 if (pgid.pool() != user_pgid.pool()) {
1657 cerr << "Can't specify a different pgid pool, must be " << pgid.pool() << std::endl;
1658 return -EINVAL;
1659 }
1660 if (pgid.is_no_shard() && !user_pgid.is_no_shard()) {
1661 cerr << "Can't specify a sharded pgid with a non-sharded export" << std::endl;
1662 return -EINVAL;
1663 }
1664 // Get shard from export information if not specified
1665 if (!pgid.is_no_shard() && user_pgid.is_no_shard()) {
1666 user_pgid.shard = pgid.shard;
1667 }
1668 if (pgid.shard != user_pgid.shard) {
1669 cerr << "Can't specify a different shard, must be " << pgid.shard << std::endl;
1670 return -EINVAL;
1671 }
1672 pgid = user_pgid;
1673 }
1674 }
1675
1676 if (!pgb.superblock.cluster_fsid.is_zero()
1677 && pgb.superblock.cluster_fsid != sb.cluster_fsid) {
1678 cerr << "Export came from different cluster with fsid "
1679 << pgb.superblock.cluster_fsid << std::endl;
1680 return -EINVAL;
1681 }
1682
1683 if (debug) {
1684 cerr << "Exported features: " << pgb.superblock.compat_features << std::endl;
1685 }
1686
1687 // Special case: Old export has SHARDS incompat feature on replicated pg, remove it
1688 if (pgid.is_no_shard())
1689 pgb.superblock.compat_features.incompat.remove(CEPH_OSD_FEATURE_INCOMPAT_SHARDS);
1690
1691 if (sb.compat_features.compare(pgb.superblock.compat_features) == -1) {
1692 CompatSet unsupported = sb.compat_features.unsupported(pgb.superblock.compat_features);
1693
1694 cerr << "Export has incompatible features set " << unsupported << std::endl;
1695
1696 // Let them import if they specify the --force option
1697 if (!force)
1698 return 11; // Positive return means exit status
1699 }
1700
1701 // Don't import if pool no longer exists
1702 OSDMap curmap;
1703 bufferlist bl;
1704 ret = get_osdmap(store, sb.current_epoch, curmap, bl);
1705 if (ret) {
1706 cerr << "Can't find local OSDMap" << std::endl;
1707 return ret;
1708 }
1709 if (!curmap.have_pg_pool(pgid.pgid.m_pool)) {
1710 cerr << "Pool " << pgid.pgid.m_pool << " no longer exists" << std::endl;
1711 // Special exit code for this error, used by test code
1712 return 10; // Positive return means exit status
1713 }
1714
1715 ghobject_t pgmeta_oid = pgid.make_pgmeta_oid();
1716 log_oid = OSD::make_pg_log_oid(pgid);
1717 biginfo_oid = OSD::make_pg_biginfo_oid(pgid);
1718
1719 //Check for PG already present.
1720 coll_t coll(pgid);
1721 if (store->collection_exists(coll)) {
1722 cerr << "pgid " << pgid << " already exists" << std::endl;
1723 return -EEXIST;
1724 }
1725
1726 if (!dry_run) {
1727 ObjectStore::Transaction t;
1728 PG::_create(t, pgid,
1729 pgid.get_split_bits(curmap.get_pg_pool(pgid.pool())->get_pg_num()));
1730 PG::_init(t, pgid, NULL);
1731
1732 // mark this coll for removal until we're done
1733 map<string,bufferlist> values;
1734 ::encode((char)1, values["_remove"]);
1735 t.omap_setkeys(coll, pgid.make_pgmeta_oid(), values);
1736
1737 store->apply_transaction(&osr, std::move(t));
1738 }
1739
1740 cout << "Importing pgid " << pgid;
1741 if (orig_pgid != pgid) {
1742 cout << " exported as " << orig_pgid;
1743 }
1744 cout << std::endl;
1745
1746 bool done = false;
1747 bool found_metadata = false;
1748 metadata_section ms;
1749 while(!done) {
1750 ret = read_section(&type, &ebl);
1751 if (ret)
1752 return ret;
1753
1754 if (debug) {
1755 cout << __func__ << ": Section type " << std::to_string(type) << std::endl;
1756 }
1757 if (type >= END_OF_TYPES) {
1758 cout << "Skipping unknown section type" << std::endl;
1759 continue;
1760 }
1761 switch(type) {
1762 case TYPE_OBJECT_BEGIN:
1763 ret = get_object(store, coll, ebl, curmap, &skipped_objects, osr);
1764 if (ret) return ret;
1765 break;
1766 case TYPE_PG_METADATA:
1767 ret = get_pg_metadata(store, ebl, ms, sb, curmap, pgid);
1768 if (ret) return ret;
1769 found_metadata = true;
1770 break;
1771 case TYPE_PG_END:
1772 done = true;
1773 break;
1774 default:
1775 cerr << "Unknown section type " << std::to_string(type) << std::endl;
1776 return -EFAULT;
1777 }
1778 }
1779
1780 if (!found_metadata) {
1781 cerr << "Missing metadata section" << std::endl;
1782 return -EFAULT;
1783 }
1784
1785 ObjectStore::Transaction t;
1786 if (!dry_run) {
1787 pg_log_t newlog, reject;
1788 pg_log_t::filter_log(pgid, curmap, g_ceph_context->_conf->osd_hit_set_namespace,
1789 ms.log, newlog, reject);
1790 if (debug) {
1791 for (list<pg_log_entry_t>::iterator i = newlog.log.begin();
1792 i != newlog.log.end(); ++i)
1793 cerr << "Keeping log entry " << *i << std::endl;
1794 for (list<pg_log_entry_t>::iterator i = reject.log.begin();
1795 i != reject.log.end(); ++i)
1796 cerr << "Skipping log entry " << *i << std::endl;
1797 }
1798
1799 divergent_priors_t newdp, rejectdp;
1800 filter_divergent_priors(pgid, curmap, g_ceph_context->_conf->osd_hit_set_namespace,
1801 ms.divergent_priors, newdp, rejectdp);
1802 ms.divergent_priors = newdp;
1803 if (debug) {
1804 for (divergent_priors_t::iterator i = newdp.begin();
1805 i != newdp.end(); ++i)
1806 cerr << "Keeping divergent_prior " << *i << std::endl;
1807 for (divergent_priors_t::iterator i = rejectdp.begin();
1808 i != rejectdp.end(); ++i)
1809 cerr << "Skipping divergent_prior " << *i << std::endl;
1810 }
1811
1812 ms.missing.filter_objects([&](const hobject_t &obj) {
1813 if (obj.nspace == g_ceph_context->_conf->osd_hit_set_namespace)
1814 return false;
1815 assert(!obj.is_temp());
1816 object_t oid = obj.oid;
1817 object_locator_t loc(obj);
1818 pg_t raw_pgid = curmap.object_locator_to_pg(oid, loc);
1819 pg_t _pgid = curmap.raw_pg_to_pg(raw_pgid);
1820
1821 return pgid.pgid != _pgid;
1822 });
1823
1824
1825 if (debug) {
1826 pg_missing_t missing;
1827 Formatter *formatter = Formatter::create("json-pretty");
1828 dump_log(formatter, cerr, newlog, ms.missing);
1829 delete formatter;
1830 }
1831
1832 // Just like a split invalidate stats since the object count is changed
1833 if (skipped_objects)
1834 ms.info.stats.stats_invalid = true;
1835
1836 ret = write_pg(
1837 t,
1838 ms.map_epoch,
1839 ms.info,
1840 newlog,
1841 ms.past_intervals,
1842 ms.divergent_priors,
1843 ms.missing);
1844 if (ret) return ret;
1845 }
1846
1847 // done, clear removal flag
1848 if (debug)
1849 cerr << "done, clearing removal flag" << std::endl;
1850
1851 if (!dry_run) {
1852 set<string> remove;
1853 remove.insert("_remove");
1854 t.omap_rmkeys(coll, pgid.make_pgmeta_oid(), remove);
1855 store->apply_transaction(&osr, std::move(t));
1856 }
1857
1858 return 0;
1859 }
1860
1861 int do_list(ObjectStore *store, string pgidstr, string object, boost::optional<std::string> nspace,
1862 Formatter *formatter, bool debug, bool human_readable, bool head)
1863 {
1864 int r;
1865 lookup_ghobject lookup(object, nspace, head);
1866 if (pgidstr.length() > 0) {
1867 r = action_on_all_objects_in_pg(store, pgidstr, lookup, debug);
1868 } else {
1869 r = action_on_all_objects(store, lookup, debug);
1870 }
1871 if (r)
1872 return r;
1873 lookup.dump(formatter, human_readable);
1874 formatter->flush(cout);
1875 return 0;
1876 }
1877
1878 int do_meta(ObjectStore *store, string object, Formatter *formatter, bool debug, bool human_readable)
1879 {
1880 int r;
1881 boost::optional<std::string> nspace; // Not specified
1882 lookup_ghobject lookup(object, nspace);
1883 r = action_on_all_objects_in_exact_pg(store, coll_t::meta(), lookup, debug);
1884 if (r)
1885 return r;
1886 lookup.dump(formatter, human_readable);
1887 formatter->flush(cout);
1888 return 0;
1889 }
1890
1891 int remove_object(coll_t coll, ghobject_t &ghobj,
1892 SnapMapper &mapper,
1893 MapCacher::Transaction<std::string, bufferlist> *_t,
1894 ObjectStore::Transaction *t)
1895 {
1896 int r = mapper.remove_oid(ghobj.hobj, _t);
1897 if (r < 0 && r != -ENOENT) {
1898 cerr << "remove_oid returned " << cpp_strerror(r) << std::endl;
1899 return r;
1900 }
1901
1902 t->remove(coll, ghobj);
1903 return 0;
1904 }
1905
1906 int get_snapset(ObjectStore *store, coll_t coll, ghobject_t &ghobj, SnapSet &ss, bool silent);
1907
1908 int do_remove_object(ObjectStore *store, coll_t coll,
1909 ghobject_t &ghobj, bool all, bool force,
1910 ObjectStore::Sequencer &osr)
1911 {
1912 spg_t pg;
1913 coll.is_pg_prefix(&pg);
1914 OSDriver driver(
1915 store,
1916 coll_t(),
1917 OSD::make_snapmapper_oid());
1918 SnapMapper mapper(g_ceph_context, &driver, 0, 0, 0, pg.shard);
1919 struct stat st;
1920
1921 int r = store->stat(coll, ghobj, &st);
1922 if (r < 0) {
1923 cerr << "remove: " << cpp_strerror(r) << std::endl;
1924 return r;
1925 }
1926
1927 SnapSet ss;
1928 if (ghobj.hobj.has_snapset()) {
1929 r = get_snapset(store, coll, ghobj, ss, false);
1930 if (r < 0) {
1931 cerr << "Can't get snapset error " << cpp_strerror(r) << std::endl;
1932 return r;
1933 }
1934 if (!ss.snaps.empty() && !all) {
1935 if (force) {
1936 cout << "WARNING: only removing "
1937 << (ghobj.hobj.is_head() ? "head" : "snapdir")
1938 << " with snapshots present" << std::endl;
1939 ss.snaps.clear();
1940 } else {
1941 cerr << "Snapshots are present, use removeall to delete everything" << std::endl;
1942 return -EINVAL;
1943 }
1944 }
1945 }
1946
1947 ObjectStore::Transaction t;
1948 OSDriver::OSTransaction _t(driver.get_transaction(&t));
1949
1950 cout << "remove " << ghobj << std::endl;
1951
1952 if (!dry_run) {
1953 r = remove_object(coll, ghobj, mapper, &_t, &t);
1954 if (r < 0)
1955 return r;
1956 }
1957
1958 ghobject_t snapobj = ghobj;
1959 for (vector<snapid_t>::iterator i = ss.snaps.begin() ;
1960 i != ss.snaps.end() ; ++i) {
1961 snapobj.hobj.snap = *i;
1962 cout << "remove " << snapobj << std::endl;
1963 if (!dry_run) {
1964 r = remove_object(coll, snapobj, mapper, &_t, &t);
1965 if (r < 0)
1966 return r;
1967 }
1968 }
1969
1970 if (!dry_run)
1971 store->apply_transaction(&osr, std::move(t));
1972
1973 return 0;
1974 }
1975
1976 int do_list_attrs(ObjectStore *store, coll_t coll, ghobject_t &ghobj)
1977 {
1978 map<string,bufferptr> aset;
1979 int r = store->getattrs(coll, ghobj, aset);
1980 if (r < 0) {
1981 cerr << "getattrs: " << cpp_strerror(r) << std::endl;
1982 return r;
1983 }
1984
1985 for (map<string,bufferptr>::iterator i = aset.begin();i != aset.end(); ++i) {
1986 string key(i->first);
1987 if (outistty)
1988 key = cleanbin(key);
1989 cout << key << std::endl;
1990 }
1991 return 0;
1992 }
1993
1994 int do_list_omap(ObjectStore *store, coll_t coll, ghobject_t &ghobj)
1995 {
1996 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(coll, ghobj);
1997 if (!iter) {
1998 cerr << "omap_get_iterator: " << cpp_strerror(ENOENT) << std::endl;
1999 return -ENOENT;
2000 }
2001 iter->seek_to_first();
2002 map<string, bufferlist> oset;
2003 while(iter->valid()) {
2004 get_omap_batch(iter, oset);
2005
2006 for (map<string,bufferlist>::iterator i = oset.begin();i != oset.end(); ++i) {
2007 string key(i->first);
2008 if (outistty)
2009 key = cleanbin(key);
2010 cout << key << std::endl;
2011 }
2012 }
2013 return 0;
2014 }
2015
2016 int do_get_bytes(ObjectStore *store, coll_t coll, ghobject_t &ghobj, int fd)
2017 {
2018 struct stat st;
2019 mysize_t total;
2020
2021 int ret = store->stat(coll, ghobj, &st);
2022 if (ret < 0) {
2023 cerr << "get-bytes: " << cpp_strerror(ret) << std::endl;
2024 return ret;
2025 }
2026
2027 total = st.st_size;
2028 if (debug)
2029 cerr << "size=" << total << std::endl;
2030
2031 uint64_t offset = 0;
2032 bufferlist rawdatabl;
2033 while(total > 0) {
2034 rawdatabl.clear();
2035 mysize_t len = max_read;
2036 if (len > total)
2037 len = total;
2038
2039 ret = store->read(coll, ghobj, offset, len, rawdatabl);
2040 if (ret < 0)
2041 return ret;
2042 if (ret == 0)
2043 return -EINVAL;
2044
2045 if (debug)
2046 cerr << "data section offset=" << offset << " len=" << len << std::endl;
2047
2048 total -= ret;
2049 offset += ret;
2050
2051 ret = write(fd, rawdatabl.c_str(), ret);
2052 if (ret == -1) {
2053 perror("write");
2054 return -errno;
2055 }
2056 }
2057
2058 return 0;
2059 }
2060
2061 int do_set_bytes(ObjectStore *store, coll_t coll,
2062 ghobject_t &ghobj, int fd,
2063 ObjectStore::Sequencer &osr)
2064 {
2065 ObjectStore::Transaction tran;
2066 ObjectStore::Transaction *t = &tran;
2067
2068 if (debug)
2069 cerr << "Write " << ghobj << std::endl;
2070
2071 if (!dry_run) {
2072 t->touch(coll, ghobj);
2073 t->truncate(coll, ghobj, 0);
2074 }
2075
2076 uint64_t offset = 0;
2077 bufferlist rawdatabl;
2078 do {
2079 rawdatabl.clear();
2080 ssize_t bytes = rawdatabl.read_fd(fd, max_read);
2081 if (bytes < 0) {
2082 cerr << "read_fd error " << cpp_strerror(bytes) << std::endl;
2083 return bytes;
2084 }
2085
2086 if (bytes == 0)
2087 break;
2088
2089 if (debug)
2090 cerr << "\tdata: offset " << offset << " bytes " << bytes << std::endl;
2091 if (!dry_run)
2092 t->write(coll, ghobj, offset, bytes, rawdatabl);
2093
2094 offset += bytes;
2095 // XXX: Should we apply_transaction() every once in a while for very large files
2096 } while(true);
2097
2098 if (!dry_run)
2099 store->apply_transaction(&osr, std::move(*t));
2100 return 0;
2101 }
2102
2103 int do_get_attr(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key)
2104 {
2105 bufferptr bp;
2106
2107 int r = store->getattr(coll, ghobj, key.c_str(), bp);
2108 if (r < 0) {
2109 cerr << "getattr: " << cpp_strerror(r) << std::endl;
2110 return r;
2111 }
2112
2113 string value(bp.c_str(), bp.length());
2114 if (outistty) {
2115 value = cleanbin(value);
2116 value.push_back('\n');
2117 }
2118 cout << value;
2119
2120 return 0;
2121 }
2122
2123 int do_set_attr(ObjectStore *store, coll_t coll,
2124 ghobject_t &ghobj, string key, int fd,
2125 ObjectStore::Sequencer &osr)
2126 {
2127 ObjectStore::Transaction tran;
2128 ObjectStore::Transaction *t = &tran;
2129 bufferlist bl;
2130
2131 if (debug)
2132 cerr << "Setattr " << ghobj << std::endl;
2133
2134 int ret = get_fd_data(fd, bl);
2135 if (ret < 0)
2136 return ret;
2137
2138 if (dry_run)
2139 return 0;
2140
2141 t->touch(coll, ghobj);
2142
2143 t->setattr(coll, ghobj, key, bl);
2144
2145 store->apply_transaction(&osr, std::move(*t));
2146 return 0;
2147 }
2148
2149 int do_rm_attr(ObjectStore *store, coll_t coll,
2150 ghobject_t &ghobj, string key,
2151 ObjectStore::Sequencer &osr)
2152 {
2153 ObjectStore::Transaction tran;
2154 ObjectStore::Transaction *t = &tran;
2155
2156 if (debug)
2157 cerr << "Rmattr " << ghobj << std::endl;
2158
2159 if (dry_run)
2160 return 0;
2161
2162 t->rmattr(coll, ghobj, key);
2163
2164 store->apply_transaction(&osr, std::move(*t));
2165 return 0;
2166 }
2167
2168 int do_get_omap(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key)
2169 {
2170 set<string> keys;
2171 map<string, bufferlist> out;
2172
2173 keys.insert(key);
2174
2175 int r = store->omap_get_values(coll, ghobj, keys, &out);
2176 if (r < 0) {
2177 cerr << "omap_get_values: " << cpp_strerror(r) << std::endl;
2178 return r;
2179 }
2180
2181 if (out.empty()) {
2182 cerr << "Key not found" << std::endl;
2183 return -ENOENT;
2184 }
2185
2186 assert(out.size() == 1);
2187
2188 bufferlist bl = out.begin()->second;
2189 string value(bl.c_str(), bl.length());
2190 if (outistty) {
2191 value = cleanbin(value);
2192 value.push_back('\n');
2193 }
2194 cout << value;
2195
2196 return 0;
2197 }
2198
2199 int do_set_omap(ObjectStore *store, coll_t coll,
2200 ghobject_t &ghobj, string key, int fd,
2201 ObjectStore::Sequencer &osr)
2202 {
2203 ObjectStore::Transaction tran;
2204 ObjectStore::Transaction *t = &tran;
2205 map<string, bufferlist> attrset;
2206 bufferlist valbl;
2207
2208 if (debug)
2209 cerr << "Set_omap " << ghobj << std::endl;
2210
2211 int ret = get_fd_data(fd, valbl);
2212 if (ret < 0)
2213 return ret;
2214
2215 attrset.insert(pair<string, bufferlist>(key, valbl));
2216
2217 if (dry_run)
2218 return 0;
2219
2220 t->touch(coll, ghobj);
2221
2222 t->omap_setkeys(coll, ghobj, attrset);
2223
2224 store->apply_transaction(&osr, std::move(*t));
2225 return 0;
2226 }
2227
2228 int do_rm_omap(ObjectStore *store, coll_t coll,
2229 ghobject_t &ghobj, string key,
2230 ObjectStore::Sequencer &osr)
2231 {
2232 ObjectStore::Transaction tran;
2233 ObjectStore::Transaction *t = &tran;
2234 set<string> keys;
2235
2236 keys.insert(key);
2237
2238 if (debug)
2239 cerr << "Rm_omap " << ghobj << std::endl;
2240
2241 if (dry_run)
2242 return 0;
2243
2244 t->omap_rmkeys(coll, ghobj, keys);
2245
2246 store->apply_transaction(&osr, std::move(*t));
2247 return 0;
2248 }
2249
2250 int do_get_omaphdr(ObjectStore *store, coll_t coll, ghobject_t &ghobj)
2251 {
2252 bufferlist hdrbl;
2253
2254 int r = store->omap_get_header(coll, ghobj, &hdrbl, true);
2255 if (r < 0) {
2256 cerr << "omap_get_header: " << cpp_strerror(r) << std::endl;
2257 return r;
2258 }
2259
2260 string header(hdrbl.c_str(), hdrbl.length());
2261 if (outistty) {
2262 header = cleanbin(header);
2263 header.push_back('\n');
2264 }
2265 cout << header;
2266
2267 return 0;
2268 }
2269
2270 int do_set_omaphdr(ObjectStore *store, coll_t coll,
2271 ghobject_t &ghobj, int fd,
2272 ObjectStore::Sequencer &osr)
2273 {
2274 ObjectStore::Transaction tran;
2275 ObjectStore::Transaction *t = &tran;
2276 bufferlist hdrbl;
2277
2278 if (debug)
2279 cerr << "Omap_setheader " << ghobj << std::endl;
2280
2281 int ret = get_fd_data(fd, hdrbl);
2282 if (ret)
2283 return ret;
2284
2285 if (dry_run)
2286 return 0;
2287
2288 t->touch(coll, ghobj);
2289
2290 t->omap_setheader(coll, ghobj, hdrbl);
2291
2292 store->apply_transaction(&osr, std::move(*t));
2293 return 0;
2294 }
2295
2296 struct do_fix_lost : public action_on_object_t {
2297 ObjectStore::Sequencer *osr;
2298
2299 explicit do_fix_lost(ObjectStore::Sequencer *_osr) : osr(_osr) {}
2300
2301 int call(ObjectStore *store, coll_t coll,
2302 ghobject_t &ghobj, object_info_t &oi) override {
2303 if (oi.is_lost()) {
2304 cout << coll << "/" << ghobj << " is lost";
2305 if (!dry_run)
2306 cout << ", fixing";
2307 cout << std::endl;
2308 if (dry_run)
2309 return 0;
2310 oi.clear_flag(object_info_t::FLAG_LOST);
2311 bufferlist bl;
2312 ::encode(oi, bl, -1); /* fixme: using full features */
2313 ObjectStore::Transaction t;
2314 t.setattr(coll, ghobj, OI_ATTR, bl);
2315 int r = store->apply_transaction(osr, std::move(t));
2316 if (r < 0) {
2317 cerr << "Error getting fixing attr on : " << make_pair(coll, ghobj)
2318 << ", "
2319 << cpp_strerror(r) << std::endl;
2320 return r;
2321 }
2322 }
2323 return 0;
2324 }
2325 };
2326
2327 int get_snapset(ObjectStore *store, coll_t coll, ghobject_t &ghobj, SnapSet &ss, bool silent = false)
2328 {
2329 bufferlist attr;
2330 int r = store->getattr(coll, ghobj, SS_ATTR, attr);
2331 if (r < 0) {
2332 if (!silent)
2333 cerr << "Error getting snapset on : " << make_pair(coll, ghobj) << ", "
2334 << cpp_strerror(r) << std::endl;
2335 return r;
2336 }
2337 bufferlist::iterator bp = attr.begin();
2338 try {
2339 ::decode(ss, bp);
2340 } catch (...) {
2341 r = -EINVAL;
2342 cerr << "Error decoding snapset on : " << make_pair(coll, ghobj) << ", "
2343 << cpp_strerror(r) << std::endl;
2344 return r;
2345 }
2346 return 0;
2347 }
2348
2349 int print_obj_info(ObjectStore *store, coll_t coll, ghobject_t &ghobj, Formatter* formatter)
2350 {
2351 int r = 0;
2352 formatter->open_object_section("obj");
2353 formatter->open_object_section("id");
2354 ghobj.dump(formatter);
2355 formatter->close_section();
2356
2357 bufferlist attr;
2358 int gr = store->getattr(coll, ghobj, OI_ATTR, attr);
2359 if (gr < 0) {
2360 r = gr;
2361 cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", "
2362 << cpp_strerror(r) << std::endl;
2363 } else {
2364 object_info_t oi;
2365 bufferlist::iterator bp = attr.begin();
2366 try {
2367 ::decode(oi, bp);
2368 formatter->open_object_section("info");
2369 oi.dump(formatter);
2370 formatter->close_section();
2371 } catch (...) {
2372 r = -EINVAL;
2373 cerr << "Error decoding attr on : " << make_pair(coll, ghobj) << ", "
2374 << cpp_strerror(r) << std::endl;
2375 }
2376 }
2377 struct stat st;
2378 int sr = store->stat(coll, ghobj, &st, true);
2379 if (sr < 0) {
2380 r = sr;
2381 cerr << "Error stat on : " << make_pair(coll, ghobj) << ", "
2382 << cpp_strerror(r) << std::endl;
2383 } else {
2384 formatter->open_object_section("stat");
2385 formatter->dump_int("size", st.st_size);
2386 formatter->dump_int("blksize", st.st_blksize);
2387 formatter->dump_int("blocks", st.st_blocks);
2388 formatter->dump_int("nlink", st.st_nlink);
2389 formatter->close_section();
2390 }
2391
2392 if (ghobj.hobj.has_snapset()) {
2393 SnapSet ss;
2394 int snr = get_snapset(store, coll, ghobj, ss);
2395 if (snr < 0) {
2396 r = snr;
2397 } else {
2398 formatter->open_object_section("SnapSet");
2399 ss.dump(formatter);
2400 formatter->close_section();
2401 }
2402 }
2403 bufferlist hattr;
2404 gr = store->getattr(coll, ghobj, ECUtil::get_hinfo_key(), hattr);
2405 if (gr == 0) {
2406 ECUtil::HashInfo hinfo;
2407 auto hp = hattr.begin();
2408 try {
2409 decode(hinfo, hp);
2410 formatter->open_object_section("hinfo");
2411 hinfo.dump(formatter);
2412 formatter->close_section();
2413 } catch (...) {
2414 r = -EINVAL;
2415 cerr << "Error decoding hinfo on : " << make_pair(coll, ghobj) << ", "
2416 << cpp_strerror(r) << std::endl;
2417 }
2418 }
2419 formatter->close_section();
2420 formatter->flush(cout);
2421 cout << std::endl;
2422 return r;
2423 }
2424
2425 int corrupt_info(ObjectStore *store, coll_t coll, ghobject_t &ghobj, Formatter* formatter,
2426 ObjectStore::Sequencer &osr)
2427 {
2428 bufferlist attr;
2429 int r = store->getattr(coll, ghobj, OI_ATTR, attr);
2430 if (r < 0) {
2431 cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", "
2432 << cpp_strerror(r) << std::endl;
2433 return r;
2434 }
2435 object_info_t oi;
2436 bufferlist::iterator bp = attr.begin();
2437 try {
2438 ::decode(oi, bp);
2439 } catch (...) {
2440 r = -EINVAL;
2441 cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", "
2442 << cpp_strerror(r) << std::endl;
2443 return r;
2444 }
2445 cout << "Corrupting info" << std::endl;
2446 if (!dry_run) {
2447 attr.clear();
2448 oi.alloc_hint_flags += 0xff;
2449 ObjectStore::Transaction t;
2450 ::encode(oi, attr, -1); /* fixme: using full features */
2451 t.setattr(coll, ghobj, OI_ATTR, attr);
2452 r = store->apply_transaction(&osr, std::move(t));
2453 if (r < 0) {
2454 cerr << "Error writing object info: " << make_pair(coll, ghobj) << ", "
2455 << cpp_strerror(r) << std::endl;
2456 return r;
2457 }
2458 }
2459 return 0;
2460 }
2461
2462 int set_size(ObjectStore *store, coll_t coll, ghobject_t &ghobj, uint64_t setsize, Formatter* formatter,
2463 ObjectStore::Sequencer &osr, bool corrupt)
2464 {
2465 if (ghobj.hobj.is_snapdir()) {
2466 cerr << "Can't set the size of a snapdir" << std::endl;
2467 return -EINVAL;
2468 }
2469 bufferlist attr;
2470 int r = store->getattr(coll, ghobj, OI_ATTR, attr);
2471 if (r < 0) {
2472 cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", "
2473 << cpp_strerror(r) << std::endl;
2474 return r;
2475 }
2476 object_info_t oi;
2477 bufferlist::iterator bp = attr.begin();
2478 try {
2479 ::decode(oi, bp);
2480 } catch (...) {
2481 r = -EINVAL;
2482 cerr << "Error getting attr on : " << make_pair(coll, ghobj) << ", "
2483 << cpp_strerror(r) << std::endl;
2484 return r;
2485 }
2486 struct stat st;
2487 r = store->stat(coll, ghobj, &st, true);
2488 if (r < 0) {
2489 cerr << "Error stat on : " << make_pair(coll, ghobj) << ", "
2490 << cpp_strerror(r) << std::endl;
2491 }
2492 ghobject_t head(ghobj);
2493 SnapSet ss;
2494 bool found_head = true;
2495 map<snapid_t, uint64_t>::iterator csi;
2496 bool is_snap = ghobj.hobj.is_snap();
2497 if (is_snap) {
2498 head.hobj = head.hobj.get_head();
2499 r = get_snapset(store, coll, head, ss, true);
2500 if (r < 0 && r != -ENOENT) {
2501 // Requested get_snapset() silent, so if not -ENOENT show error
2502 cerr << "Error getting snapset on : " << make_pair(coll, head) << ", "
2503 << cpp_strerror(r) << std::endl;
2504 return r;
2505 }
2506 if (r == -ENOENT) {
2507 head.hobj = head.hobj.get_snapdir();
2508 r = get_snapset(store, coll, head, ss);
2509 if (r < 0)
2510 return r;
2511 found_head = false;
2512 } else {
2513 found_head = true;
2514 }
2515 csi = ss.clone_size.find(ghobj.hobj.snap);
2516 if (csi == ss.clone_size.end()) {
2517 cerr << "SnapSet is missing clone_size for snap " << ghobj.hobj.snap << std::endl;
2518 return -EINVAL;
2519 }
2520 }
2521 if ((uint64_t)st.st_size == setsize && oi.size == setsize
2522 && (!is_snap || csi->second == setsize)) {
2523 cout << "Size of object is already " << setsize << std::endl;
2524 return 0;
2525 }
2526 cout << "Setting size to " << setsize << ", stat size " << st.st_size
2527 << ", obj info size " << oi.size;
2528 if (is_snap) {
2529 cout << ", " << (found_head ? "head" : "snapdir")
2530 << " clone_size " << csi->second;
2531 csi->second = setsize;
2532 }
2533 cout << std::endl;
2534 if (!dry_run) {
2535 attr.clear();
2536 oi.size = setsize;
2537 ObjectStore::Transaction t;
2538 // Only modify object info if we want to corrupt it
2539 if (!corrupt && (uint64_t)st.st_size != setsize) {
2540 t.truncate(coll, ghobj, setsize);
2541 // Changing objectstore size will invalidate data_digest, so clear it.
2542 oi.clear_data_digest();
2543 }
2544 ::encode(oi, attr, -1); /* fixme: using full features */
2545 t.setattr(coll, ghobj, OI_ATTR, attr);
2546 if (is_snap) {
2547 bufferlist snapattr;
2548 snapattr.clear();
2549 ::encode(ss, snapattr);
2550 t.setattr(coll, head, SS_ATTR, snapattr);
2551 }
2552 r = store->apply_transaction(&osr, std::move(t));
2553 if (r < 0) {
2554 cerr << "Error writing object info: " << make_pair(coll, ghobj) << ", "
2555 << cpp_strerror(r) << std::endl;
2556 return r;
2557 }
2558 }
2559 return 0;
2560 }
2561
2562 int clear_snapset(ObjectStore *store, coll_t coll, ghobject_t &ghobj,
2563 string arg, ObjectStore::Sequencer &osr)
2564 {
2565 SnapSet ss;
2566 int ret = get_snapset(store, coll, ghobj, ss);
2567 if (ret < 0)
2568 return ret;
2569
2570 // Use "head" to set head_exists incorrectly
2571 if (arg == "corrupt" || arg == "head")
2572 ss.head_exists = !ghobj.hobj.is_head();
2573 else if (ss.head_exists != ghobj.hobj.is_head()) {
2574 cerr << "Correcting head_exists, set to "
2575 << (ghobj.hobj.is_head() ? "true" : "false") << std::endl;
2576 ss.head_exists = ghobj.hobj.is_head();
2577 }
2578 // Use "corrupt" to clear entire SnapSet
2579 // Use "seq" to just corrupt SnapSet.seq
2580 if (arg == "corrupt" || arg == "seq")
2581 ss.seq = 0;
2582 // Use "snaps" to just clear SnapSet.snaps
2583 if (arg == "corrupt" || arg == "snaps")
2584 ss.snaps.clear();
2585 // By default just clear clone, clone_overlap and clone_size
2586 if (arg == "corrupt")
2587 arg = "";
2588 if (arg == "" || arg == "clones")
2589 ss.clones.clear();
2590 if (arg == "" || arg == "clone_overlap")
2591 ss.clone_overlap.clear();
2592 if (arg == "" || arg == "clone_size")
2593 ss.clone_size.clear();
2594 // Break all clone sizes by adding 1
2595 if (arg == "size") {
2596 for (map<snapid_t, uint64_t>::iterator i = ss.clone_size.begin();
2597 i != ss.clone_size.end(); ++i)
2598 ++(i->second);
2599 }
2600
2601 if (!dry_run) {
2602 bufferlist bl;
2603 ::encode(ss, bl);
2604 ObjectStore::Transaction t;
2605 t.setattr(coll, ghobj, SS_ATTR, bl);
2606 int r = store->apply_transaction(&osr, std::move(t));
2607 if (r < 0) {
2608 cerr << "Error setting snapset on : " << make_pair(coll, ghobj) << ", "
2609 << cpp_strerror(r) << std::endl;
2610 return r;
2611 }
2612 }
2613 return 0;
2614 }
2615
2616 vector<snapid_t>::iterator find(vector<snapid_t> &v, snapid_t clid)
2617 {
2618 return std::find(v.begin(), v.end(), clid);
2619 }
2620
2621 map<snapid_t, interval_set<uint64_t> >::iterator
2622 find(map<snapid_t, interval_set<uint64_t> > &m, snapid_t clid)
2623 {
2624 return m.find(clid);
2625 }
2626
2627 map<snapid_t, uint64_t>::iterator find(map<snapid_t, uint64_t> &m,
2628 snapid_t clid)
2629 {
2630 return m.find(clid);
2631 }
2632
2633 template<class T>
2634 int remove_from(T &mv, string name, snapid_t cloneid, bool force)
2635 {
2636 typename T::iterator i = find(mv, cloneid);
2637 if (i != mv.end()) {
2638 mv.erase(i);
2639 } else {
2640 cerr << "Clone " << cloneid << " doesn't exist in " << name;
2641 if (force) {
2642 cerr << " (ignored)" << std::endl;
2643 return 0;
2644 }
2645 cerr << std::endl;
2646 return -EINVAL;
2647 }
2648 return 0;
2649 }
2650
2651 int remove_clone(ObjectStore *store, coll_t coll, ghobject_t &ghobj, snapid_t cloneid, bool force,
2652 ObjectStore::Sequencer &osr)
2653 {
2654 // XXX: Don't allow this if in a cache tier or former cache tier
2655 // bool allow_incomplete_clones() const {
2656 // return cache_mode != CACHEMODE_NONE || has_flag(FLAG_INCOMPLETE_CLONES);
2657
2658 SnapSet snapset;
2659 int ret = get_snapset(store, coll, ghobj, snapset);
2660 if (ret < 0)
2661 return ret;
2662
2663 // Derived from trim_object()
2664 // ...from snapset
2665 vector<snapid_t>::iterator p;
2666 for (p = snapset.clones.begin(); p != snapset.clones.end(); ++p)
2667 if (*p == cloneid)
2668 break;
2669 if (p == snapset.clones.end()) {
2670 cerr << "Clone " << cloneid << " not present";
2671 return -ENOENT;
2672 }
2673 if (p != snapset.clones.begin()) {
2674 // not the oldest... merge overlap into next older clone
2675 vector<snapid_t>::iterator n = p - 1;
2676 hobject_t prev_coid = ghobj.hobj;
2677 prev_coid.snap = *n;
2678 //bool adjust_prev_bytes = is_present_clone(prev_coid);
2679
2680 //if (adjust_prev_bytes)
2681 // ctx->delta_stats.num_bytes -= snapset.get_clone_bytes(*n);
2682
2683 snapset.clone_overlap[*n].intersection_of(
2684 snapset.clone_overlap[*p]);
2685
2686 //if (adjust_prev_bytes)
2687 // ctx->delta_stats.num_bytes += snapset.get_clone_bytes(*n);
2688 }
2689
2690 ret = remove_from(snapset.clones, "clones", cloneid, force);
2691 if (ret) return ret;
2692 ret = remove_from(snapset.clone_overlap, "clone_overlap", cloneid, force);
2693 if (ret) return ret;
2694 ret = remove_from(snapset.clone_size, "clone_size", cloneid, force);
2695 if (ret) return ret;
2696
2697 if (dry_run)
2698 return 0;
2699
2700 bufferlist bl;
2701 ::encode(snapset, bl);
2702 ObjectStore::Transaction t;
2703 t.setattr(coll, ghobj, SS_ATTR, bl);
2704 int r = store->apply_transaction(&osr, std::move(t));
2705 if (r < 0) {
2706 cerr << "Error setting snapset on : " << make_pair(coll, ghobj) << ", "
2707 << cpp_strerror(r) << std::endl;
2708 return r;
2709 }
2710 cout << "Removal of clone " << cloneid << " complete" << std::endl;
2711 cout << "Use pg repair after OSD restarted to correct stat information" << std::endl;
2712 return 0;
2713 }
2714
2715 int dup(string srcpath, ObjectStore *src, string dstpath, ObjectStore *dst)
2716 {
2717 cout << "dup from " << src->get_type() << ": " << srcpath << "\n"
2718 << " to " << dst->get_type() << ": " << dstpath
2719 << std::endl;
2720 ObjectStore::Sequencer osr("dup");
2721 int num, i;
2722 vector<coll_t> collections;
2723 int r;
2724
2725 r = src->mount();
2726 if (r < 0) {
2727 cerr << "failed to mount src: " << cpp_strerror(r) << std::endl;
2728 return r;
2729 }
2730 r = dst->mount();
2731 if (r < 0) {
2732 cerr << "failed to mount dst: " << cpp_strerror(r) << std::endl;
2733 goto out_src;
2734 }
2735
2736 if (src->get_fsid() != dst->get_fsid()) {
2737 cerr << "src fsid " << src->get_fsid() << " != dest " << dst->get_fsid()
2738 << std::endl;
2739 goto out;
2740 }
2741 cout << "fsid " << src->get_fsid() << std::endl;
2742
2743 // make sure dst is empty
2744 r = dst->list_collections(collections);
2745 if (r < 0) {
2746 cerr << "error listing collections on dst: " << cpp_strerror(r) << std::endl;
2747 goto out;
2748 }
2749 if (!collections.empty()) {
2750 cerr << "destination store is not empty" << std::endl;
2751 goto out;
2752 }
2753
2754 r = src->list_collections(collections);
2755 if (r < 0) {
2756 cerr << "error listing collections on src: " << cpp_strerror(r) << std::endl;
2757 goto out;
2758 }
2759
2760 num = collections.size();
2761 cout << num << " collections" << std::endl;
2762 i = 1;
2763 for (auto cid : collections) {
2764 cout << i++ << "/" << num << " " << cid << std::endl;
2765 {
2766 ObjectStore::Transaction t;
2767 int bits = src->collection_bits(cid);
2768 if (bits < 0) {
2769 if (src->get_type() == "filestore" && cid.is_meta()) {
2770 bits = 0;
2771 } else {
2772 cerr << "cannot get bit count for collection " << cid << ": "
2773 << cpp_strerror(bits) << std::endl;
2774 goto out;
2775 }
2776 }
2777 t.create_collection(cid, bits);
2778 dst->apply_transaction(&osr, std::move(t));
2779 }
2780
2781 ghobject_t pos;
2782 uint64_t n = 0;
2783 uint64_t bytes = 0, keys = 0;
2784 while (true) {
2785 vector<ghobject_t> ls;
2786 r = src->collection_list(cid, pos, ghobject_t::get_max(), 1000, &ls, &pos);
2787 if (r < 0) {
2788 cerr << "collection_list on " << cid << " from " << pos << " got: "
2789 << cpp_strerror(r) << std::endl;
2790 goto out;
2791 }
2792 if (ls.empty()) {
2793 break;
2794 }
2795
2796 for (auto& oid : ls) {
2797 //cout << " " << cid << " " << oid << std::endl;
2798 if (n % 100 == 0) {
2799 cout << " " << std::setw(16) << n << " objects, "
2800 << std::setw(16) << bytes << " bytes, "
2801 << std::setw(16) << keys << " keys"
2802 << std::setw(1) << "\r" << std::flush;
2803 }
2804 n++;
2805
2806 ObjectStore::Transaction t;
2807 t.touch(cid, oid);
2808
2809 map<string,bufferptr> attrs;
2810 src->getattrs(cid, oid, attrs);
2811 if (!attrs.empty()) {
2812 t.setattrs(cid, oid, attrs);
2813 }
2814
2815 bufferlist bl;
2816 src->read(cid, oid, 0, 0, bl);
2817 if (bl.length()) {
2818 t.write(cid, oid, 0, bl.length(), bl);
2819 bytes += bl.length();
2820 }
2821
2822 bufferlist header;
2823 map<string,bufferlist> omap;
2824 src->omap_get(cid, oid, &header, &omap);
2825 if (header.length()) {
2826 t.omap_setheader(cid, oid, header);
2827 ++keys;
2828 }
2829 if (!omap.empty()) {
2830 keys += omap.size();
2831 t.omap_setkeys(cid, oid, omap);
2832 }
2833
2834 dst->apply_transaction(&osr, std::move(t));
2835 }
2836 }
2837 cout << " " << std::setw(16) << n << " objects, "
2838 << std::setw(16) << bytes << " bytes, "
2839 << std::setw(16) << keys << " keys"
2840 << std::setw(1) << std::endl;
2841 }
2842
2843 // keyring
2844 cout << "keyring" << std::endl;
2845 {
2846 bufferlist bl;
2847 string s = srcpath + "/keyring";
2848 string err;
2849 r = bl.read_file(s.c_str(), &err);
2850 if (r < 0) {
2851 cerr << "failed to copy " << s << ": " << err << std::endl;
2852 } else {
2853 string d = dstpath + "/keyring";
2854 bl.write_file(d.c_str(), 0600);
2855 }
2856 }
2857
2858 // osd metadata
2859 cout << "duping osd metadata" << std::endl;
2860 {
2861 for (auto k : {"magic", "whoami", "ceph_fsid", "fsid"}) {
2862 string val;
2863 src->read_meta(k, &val);
2864 dst->write_meta(k, val);
2865 }
2866 }
2867
2868 dst->write_meta("ready", "ready");
2869
2870 cout << "done." << std::endl;
2871 r = 0;
2872 out:
2873 dst->umount();
2874 out_src:
2875 src->umount();
2876 return r;
2877 }
2878
2879 void usage(po::options_description &desc)
2880 {
2881 cerr << std::endl;
2882 cerr << desc << std::endl;
2883 cerr << std::endl;
2884 cerr << "Positional syntax:" << std::endl;
2885 cerr << std::endl;
2886 cerr << "ceph-objectstore-tool ... <object> (get|set)-bytes [file]" << std::endl;
2887 cerr << "ceph-objectstore-tool ... <object> set-(attr|omap) <key> [file]" << std::endl;
2888 cerr << "ceph-objectstore-tool ... <object> (get|rm)-(attr|omap) <key>" << std::endl;
2889 cerr << "ceph-objectstore-tool ... <object> get-omaphdr" << std::endl;
2890 cerr << "ceph-objectstore-tool ... <object> set-omaphdr [file]" << std::endl;
2891 cerr << "ceph-objectstore-tool ... <object> list-attrs" << std::endl;
2892 cerr << "ceph-objectstore-tool ... <object> list-omap" << std::endl;
2893 cerr << "ceph-objectstore-tool ... <object> remove|removeall" << std::endl;
2894 cerr << "ceph-objectstore-tool ... <object> dump" << std::endl;
2895 cerr << "ceph-objectstore-tool ... <object> set-size" << std::endl;
2896 cerr << "ceph-objectstore-tool ... <object> remove-clone-metadata <cloneid>" << std::endl;
2897 cerr << std::endl;
2898 cerr << "<object> can be a JSON object description as displayed" << std::endl;
2899 cerr << "by --op list." << std::endl;
2900 cerr << "<object> can be an object name which will be looked up in all" << std::endl;
2901 cerr << "the OSD's PGs." << std::endl;
2902 cerr << "<object> can be the empty string ('') which with a provided pgid " << std::endl;
2903 cerr << "specifies the pgmeta object" << std::endl;
2904 cerr << std::endl;
2905 cerr << "The optional [file] argument will read stdin or write stdout" << std::endl;
2906 cerr << "if not specified or if '-' specified." << std::endl;
2907 }
2908
2909 bool ends_with(const string& check, const string& ending)
2910 {
2911 return check.size() >= ending.size() && check.rfind(ending) == (check.size() - ending.size());
2912 }
2913
2914 // Based on FileStore::dump_journal(), set-up enough to only dump
2915 int mydump_journal(Formatter *f, string journalpath, bool m_journal_dio)
2916 {
2917 int r;
2918
2919 if (!journalpath.length())
2920 return -EINVAL;
2921
2922 FileJournal *journal = new FileJournal(g_ceph_context, uuid_d(), NULL, NULL,
2923 journalpath.c_str(), m_journal_dio);
2924 r = journal->_fdump(*f, false);
2925 delete journal;
2926 return r;
2927 }
2928
2929 int apply_layout_settings(ObjectStore *os, const OSDSuperblock &superblock,
2930 const string &pool_name, const spg_t &pgid, bool dry_run,
2931 int target_level)
2932 {
2933 int r = 0;
2934
2935 FileStore *fs = dynamic_cast<FileStore*>(os);
2936 if (!fs) {
2937 cerr << "Nothing to do for non-filestore backend" << std::endl;
2938 return 0; // making this return success makes testing easier
2939 }
2940
2941 OSDMap curmap;
2942 bufferlist bl;
2943 r = get_osdmap(os, superblock.current_epoch, curmap, bl);
2944 if (r) {
2945 cerr << "Can't find local OSDMap: " << cpp_strerror(r) << std::endl;
2946 return r;
2947 }
2948
2949 int64_t poolid = -1;
2950 if (pool_name.length()) {
2951 poolid = curmap.lookup_pg_pool_name(pool_name);
2952 if (poolid < 0) {
2953 cerr << "Couldn't find pool " << pool_name << ": " << cpp_strerror(poolid)
2954 << std::endl;
2955 return poolid;
2956 }
2957 }
2958
2959 vector<coll_t> collections, filtered_colls;
2960 r = os->list_collections(collections);
2961 if (r < 0) {
2962 cerr << "Error listing collections: " << cpp_strerror(r) << std::endl;
2963 return r;
2964 }
2965
2966 for (auto const &coll : collections) {
2967 spg_t coll_pgid;
2968 if (coll.is_pg(&coll_pgid) &&
2969 ((poolid >= 0 && coll_pgid.pool() == (uint64_t)poolid) ||
2970 coll_pgid == pgid)) {
2971 filtered_colls.push_back(coll);
2972 }
2973 }
2974
2975 size_t done = 0, total = filtered_colls.size();
2976 for (auto const &coll : filtered_colls) {
2977 if (dry_run) {
2978 cerr << "Would apply layout settings to " << coll << std::endl;
2979 } else {
2980 cerr << "Finished " << done << "/" << total << " collections" << "\r";
2981 r = fs->apply_layout_settings(coll, target_level);
2982 if (r < 0) {
2983 cerr << "Error applying layout settings to " << coll << std::endl;
2984 return r;
2985 }
2986 }
2987 ++done;
2988 }
2989
2990 cerr << "Finished " << total << "/" << total << " collections" << "\r" << std::endl;
2991 return r;
2992 }
2993
2994 int main(int argc, char **argv)
2995 {
2996 string dpath, jpath, pgidstr, op, file, mountpoint, mon_store_path, object;
2997 string target_data_path, fsid;
2998 string objcmd, arg1, arg2, type, format, argnspace, pool;
2999 boost::optional<std::string> nspace;
3000 spg_t pgid;
3001 unsigned epoch = 0;
3002 ghobject_t ghobj;
3003 bool human_readable;
3004 bool force;
3005 Formatter *formatter;
3006 bool head;
3007
3008 po::options_description desc("Allowed options");
3009 desc.add_options()
3010 ("help", "produce help message")
3011 ("type", po::value<string>(&type),
3012 "Arg is one of [bluestore, filestore (default), memstore]")
3013 ("data-path", po::value<string>(&dpath),
3014 "path to object store, mandatory")
3015 ("journal-path", po::value<string>(&jpath),
3016 "path to journal, use if tool can't find it")
3017 ("pgid", po::value<string>(&pgidstr),
3018 "PG id, mandatory for info, log, remove, export, export-remove, rm-past-intervals, mark-complete, trim-pg-log, and mandatory for apply-layout-settings if --pool is not specified")
3019 ("pool", po::value<string>(&pool),
3020 "Pool name, mandatory for apply-layout-settings if --pgid is not specified")
3021 ("op", po::value<string>(&op),
3022 "Arg is one of [info, log, remove, mkfs, fsck, repair, fuse, dup, export, export-remove, import, list, fix-lost, list-pgs, rm-past-intervals, dump-journal, dump-super, meta-list, "
3023 "get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, apply-layout-settings, update-mon-db, dump-import, trim-pg-log]")
3024 ("epoch", po::value<unsigned>(&epoch),
3025 "epoch# for get-osdmap and get-inc-osdmap, the current epoch in use if not specified")
3026 ("file", po::value<string>(&file),
3027 "path of file to export, export-remove, import, get-osdmap, set-osdmap, get-inc-osdmap or set-inc-osdmap")
3028 ("mon-store-path", po::value<string>(&mon_store_path),
3029 "path of monstore to update-mon-db")
3030 ("fsid", po::value<string>(&fsid),
3031 "fsid for new store created by mkfs")
3032 ("target-data-path", po::value<string>(&target_data_path),
3033 "path of target object store (for --op dup)")
3034 ("mountpoint", po::value<string>(&mountpoint),
3035 "fuse mountpoint")
3036 ("format", po::value<string>(&format)->default_value("json-pretty"),
3037 "Output format which may be json, json-pretty, xml, xml-pretty")
3038 ("debug", "Enable diagnostic output to stderr")
3039 ("force", "Ignore some types of errors and proceed with operation - USE WITH CAUTION: CORRUPTION POSSIBLE NOW OR IN THE FUTURE")
3040 ("skip-journal-replay", "Disable journal replay")
3041 ("skip-mount-omap", "Disable mounting of omap")
3042 ("head", "Find head/snapdir when searching for objects by name")
3043 ("dry-run", "Don't modify the objectstore")
3044 ("namespace", po::value<string>(&argnspace), "Specify namespace when searching for objects")
3045 ;
3046
3047 po::options_description positional("Positional options");
3048 positional.add_options()
3049 ("object", po::value<string>(&object), "'' for pgmeta_oid, object name or ghobject in json")
3050 ("objcmd", po::value<string>(&objcmd), "command [(get|set)-bytes, (get|set|rm)-(attr|omap), (get|set)-omaphdr, list-attrs, list-omap, remove]")
3051 ("arg1", po::value<string>(&arg1), "arg1 based on cmd")
3052 ("arg2", po::value<string>(&arg2), "arg2 based on cmd")
3053 ;
3054
3055 po::options_description all;
3056 all.add(desc).add(positional);
3057
3058 po::positional_options_description pd;
3059 pd.add("object", 1).add("objcmd", 1).add("arg1", 1).add("arg2", 1);
3060
3061 vector<string> ceph_option_strings;
3062 po::variables_map vm;
3063 try {
3064 po::parsed_options parsed =
3065 po::command_line_parser(argc, argv).options(all).allow_unregistered().positional(pd).run();
3066 po::store( parsed, vm);
3067 po::notify(vm);
3068 ceph_option_strings = po::collect_unrecognized(parsed.options,
3069 po::include_positional);
3070 } catch(po::error &e) {
3071 std::cerr << e.what() << std::endl;
3072 return 1;
3073 }
3074
3075 if (vm.count("help")) {
3076 usage(desc);
3077 return 1;
3078 }
3079
3080 debug = (vm.count("debug") > 0);
3081
3082 force = (vm.count("force") > 0);
3083
3084 if (vm.count("namespace"))
3085 nspace = argnspace;
3086
3087 dry_run = (vm.count("dry-run") > 0);
3088
3089 osflagbits_t flags = 0;
3090 if (dry_run || vm.count("skip-journal-replay"))
3091 flags |= SKIP_JOURNAL_REPLAY;
3092 if (vm.count("skip-mount-omap"))
3093 flags |= SKIP_MOUNT_OMAP;
3094 if (op == "update-mon-db")
3095 flags |= SKIP_JOURNAL_REPLAY;
3096
3097 head = (vm.count("head") > 0);
3098
3099 vector<const char *> ceph_options;
3100 env_to_vec(ceph_options);
3101 ceph_options.reserve(ceph_options.size() + ceph_option_strings.size());
3102 for (vector<string>::iterator i = ceph_option_strings.begin();
3103 i != ceph_option_strings.end();
3104 ++i) {
3105 ceph_options.push_back(i->c_str());
3106 }
3107
3108 char fn[PATH_MAX];
3109 snprintf(fn, sizeof(fn), "%s/type", dpath.c_str());
3110 int fd = ::open(fn, O_RDONLY);
3111 if (fd >= 0) {
3112 bufferlist bl;
3113 bl.read_fd(fd, 64);
3114 if (bl.length()) {
3115 string dp_type = string(bl.c_str(), bl.length() - 1); // drop \n
3116 if (vm.count("type") && dp_type != "" && type != dp_type)
3117 cerr << "WARNING: Ignoring type \"" << type << "\" - found data-path type \""
3118 << dp_type << "\"" << std::endl;
3119 type = dp_type;
3120 //cout << "object store type is " << type << std::endl;
3121 }
3122 ::close(fd);
3123 }
3124 if (!vm.count("type") && type == "") {
3125 type = "filestore";
3126 }
3127 if (!vm.count("data-path") &&
3128 op != "dump-import" &&
3129 !(op == "dump-journal" && type == "filestore")) {
3130 cerr << "Must provide --data-path" << std::endl;
3131 usage(desc);
3132 return 1;
3133 }
3134 if (type == "filestore" && !vm.count("journal-path")) {
3135 jpath = dpath + "/journal";
3136 }
3137 if (!vm.count("op") && !vm.count("object")) {
3138 cerr << "Must provide --op or object command..." << std::endl;
3139 usage(desc);
3140 return 1;
3141 }
3142 if (op != "list" && op != "apply-layout-settings" &&
3143 vm.count("op") && vm.count("object")) {
3144 cerr << "Can't specify both --op and object command syntax" << std::endl;
3145 usage(desc);
3146 return 1;
3147 }
3148 if (op == "apply-layout-settings" && !(vm.count("pool") ^ vm.count("pgid"))) {
3149 cerr << "apply-layout-settings requires either --pool or --pgid"
3150 << std::endl;
3151 usage(desc);
3152 return 1;
3153 }
3154 if (op != "list" && op != "apply-layout-settings" && vm.count("object") && !vm.count("objcmd")) {
3155 cerr << "Invalid syntax, missing command" << std::endl;
3156 usage(desc);
3157 return 1;
3158 }
3159 if (op == "fuse" && mountpoint.length() == 0) {
3160 cerr << "Missing fuse mountpoint" << std::endl;
3161 usage(desc);
3162 return 1;
3163 }
3164 outistty = isatty(STDOUT_FILENO);
3165
3166 file_fd = fd_none;
3167 if ((op == "export" || op == "export-remove" || op == "get-osdmap" || op == "get-inc-osdmap") && !dry_run) {
3168 if (!vm.count("file") || file == "-") {
3169 if (outistty) {
3170 cerr << "stdout is a tty and no --file filename specified" << std::endl;
3171 return 1;
3172 }
3173 file_fd = STDOUT_FILENO;
3174 } else {
3175 file_fd = open(file.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
3176 }
3177 } else if (op == "import" || op == "dump-import" || op == "set-osdmap" || op == "set-inc-osdmap") {
3178 if (!vm.count("file") || file == "-") {
3179 if (isatty(STDIN_FILENO)) {
3180 cerr << "stdin is a tty and no --file filename specified" << std::endl;
3181 return 1;
3182 }
3183 file_fd = STDIN_FILENO;
3184 } else {
3185 file_fd = open(file.c_str(), O_RDONLY);
3186 }
3187 }
3188
3189 ObjectStoreTool tool = ObjectStoreTool(file_fd, dry_run);
3190
3191 if (vm.count("file") && file_fd == fd_none && !dry_run) {
3192 cerr << "--file option only applies to import, dump-import, export, export-remove, "
3193 << "get-osdmap, set-osdmap, get-inc-osdmap or set-inc-osdmap" << std::endl;
3194 return 1;
3195 }
3196
3197 if (file_fd != fd_none && file_fd < 0) {
3198 string err = string("file: ") + file;
3199 perror(err.c_str());
3200 return 1;
3201 }
3202
3203 auto cct = global_init(
3204 NULL, ceph_options, CEPH_ENTITY_TYPE_OSD,
3205 CODE_ENVIRONMENT_UTILITY_NODOUT, 0);
3206 //CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
3207 common_init_finish(g_ceph_context);
3208 g_conf = g_ceph_context->_conf;
3209 if (debug) {
3210 g_conf->set_val_or_die("log_to_stderr", "true");
3211 g_conf->set_val_or_die("err_to_stderr", "true");
3212 }
3213 g_conf->apply_changes(NULL);
3214
3215 // Special list handling. Treating pretty_format as human readable,
3216 // with one object per line and not an enclosing array.
3217 human_readable = ends_with(format, "-pretty");
3218 if ((op == "list" || op == "meta-list") && human_readable) {
3219 // Remove -pretty from end of format which we know is there
3220 format = format.substr(0, format.size() - strlen("-pretty"));
3221 }
3222
3223 formatter = Formatter::create(format);
3224 if (formatter == NULL) {
3225 cerr << "unrecognized format: " << format << std::endl;
3226 return 1;
3227 }
3228
3229 // Special handling for filestore journal, so we can dump it without mounting
3230 if (op == "dump-journal" && type == "filestore") {
3231 int ret = mydump_journal(formatter, jpath, g_conf->journal_dio);
3232 if (ret < 0) {
3233 cerr << "journal-path: " << jpath << ": "
3234 << cpp_strerror(ret) << std::endl;
3235 return 1;
3236 }
3237 formatter->flush(cout);
3238 return 0;
3239 }
3240
3241 if (op == "dump-import") {
3242 int ret = tool.dump_import(formatter);
3243 if (ret < 0) {
3244 cerr << "dump-import: "
3245 << cpp_strerror(ret) << std::endl;
3246 return 1;
3247 }
3248 return 0;
3249 }
3250
3251 //Verify that data-path really exists
3252 struct stat st;
3253 if (::stat(dpath.c_str(), &st) == -1) {
3254 string err = string("data-path: ") + dpath;
3255 perror(err.c_str());
3256 return 1;
3257 }
3258
3259 if (pgidstr.length() && !pgid.parse(pgidstr.c_str())) {
3260 cerr << "Invalid pgid '" << pgidstr << "' specified" << std::endl;
3261 return 1;
3262 }
3263
3264 //Verify that the journal-path really exists
3265 if (type == "filestore") {
3266 if (::stat(jpath.c_str(), &st) == -1) {
3267 string err = string("journal-path: ") + jpath;
3268 perror(err.c_str());
3269 return 1;
3270 }
3271 if (S_ISDIR(st.st_mode)) {
3272 cerr << "journal-path: " << jpath << ": "
3273 << cpp_strerror(EISDIR) << std::endl;
3274 return 1;
3275 }
3276 }
3277
3278 ObjectStore *fs = ObjectStore::create(g_ceph_context, type, dpath, jpath, flags);
3279 if (fs == NULL) {
3280 cerr << "Unable to create store of type " << type << std::endl;
3281 return 1;
3282 }
3283
3284 if (op == "fsck" || op == "fsck-deep") {
3285 int r = fs->fsck(op == "fsck-deep");
3286 if (r < 0) {
3287 cerr << "fsck failed: " << cpp_strerror(r) << std::endl;
3288 return 1;
3289 }
3290 if (r > 0) {
3291 cerr << "fsck found " << r << " errors" << std::endl;
3292 return 1;
3293 }
3294 cout << "fsck found no errors" << std::endl;
3295 return 0;
3296 }
3297 if (op == "repair" || op == "repair-deep") {
3298 int r = fs->repair(op == "repair-deep");
3299 if (r < 0) {
3300 cerr << "repair failed: " << cpp_strerror(r) << std::endl;
3301 return 1;
3302 }
3303 if (r > 0) {
3304 cerr << "repair found " << r << " errors" << std::endl;
3305 return 1;
3306 }
3307 cout << "repair found no errors" << std::endl;
3308 return 0;
3309 }
3310 if (op == "mkfs") {
3311 if (fsid.length()) {
3312 uuid_d f;
3313 bool r = f.parse(fsid.c_str());
3314 if (!r) {
3315 cerr << "failed to parse uuid '" << fsid << "'" << std::endl;
3316 return 1;
3317 }
3318 fs->set_fsid(f);
3319 }
3320 int r = fs->mkfs();
3321 if (r < 0) {
3322 cerr << "mkfs failed: " << cpp_strerror(r) << std::endl;
3323 return 1;
3324 }
3325 return 0;
3326 }
3327 if (op == "dup") {
3328 string target_type;
3329 char fn[PATH_MAX];
3330 snprintf(fn, sizeof(fn), "%s/type", target_data_path.c_str());
3331 int fd = ::open(fn, O_RDONLY);
3332 if (fd < 0) {
3333 cerr << "Unable to open " << target_data_path << "/type" << std::endl;
3334 exit(1);
3335 }
3336 bufferlist bl;
3337 bl.read_fd(fd, 64);
3338 if (bl.length()) {
3339 target_type = string(bl.c_str(), bl.length() - 1); // drop \n
3340 }
3341 ::close(fd);
3342 ObjectStore *targetfs = ObjectStore::create(
3343 g_ceph_context, target_type,
3344 target_data_path, "", 0);
3345 if (targetfs == NULL) {
3346 cerr << "Unable to open store of type " << target_type << std::endl;
3347 return 1;
3348 }
3349 int r = dup(dpath, fs, target_data_path, targetfs);
3350 if (r < 0) {
3351 cerr << "dup failed: " << cpp_strerror(r) << std::endl;
3352 return 1;
3353 }
3354 return 0;
3355 }
3356
3357 ObjectStore::Sequencer *osr = new ObjectStore::Sequencer(__func__);
3358 int ret = fs->mount();
3359 if (ret < 0) {
3360 if (ret == -EBUSY) {
3361 cerr << "OSD has the store locked" << std::endl;
3362 } else {
3363 cerr << "Mount failed with '" << cpp_strerror(ret) << "'" << std::endl;
3364 }
3365 return 1;
3366 }
3367
3368 if (op == "fuse") {
3369 #ifdef HAVE_LIBFUSE
3370 FuseStore fuse(fs, mountpoint);
3371 cout << "mounting fuse at " << mountpoint << " ..." << std::endl;
3372 int r = fuse.main();
3373 if (r < 0) {
3374 cerr << "failed to mount fuse: " << cpp_strerror(r) << std::endl;
3375 return 1;
3376 }
3377 #else
3378 cerr << "fuse support not enabled" << std::endl;
3379 #endif
3380 return 0;
3381 }
3382
3383 vector<coll_t> ls;
3384 vector<coll_t>::iterator it;
3385 CompatSet supported;
3386
3387 #ifdef INTERNAL_TEST
3388 supported = get_test_compat_set();
3389 #else
3390 supported = OSD::get_osd_compat_set();
3391 #endif
3392
3393 bufferlist bl;
3394 OSDSuperblock superblock;
3395 bufferlist::iterator p;
3396 ret = fs->read(coll_t::meta(), OSD_SUPERBLOCK_GOBJECT, 0, 0, bl);
3397 if (ret < 0) {
3398 cerr << "Failure to read OSD superblock: " << cpp_strerror(ret) << std::endl;
3399 goto out;
3400 }
3401
3402 p = bl.begin();
3403 ::decode(superblock, p);
3404
3405 if (debug) {
3406 cerr << "Cluster fsid=" << superblock.cluster_fsid << std::endl;
3407 }
3408
3409 if (debug) {
3410 cerr << "Supported features: " << supported << std::endl;
3411 cerr << "On-disk features: " << superblock.compat_features << std::endl;
3412 }
3413 if (supported.compare(superblock.compat_features) == -1) {
3414 CompatSet unsupported = supported.unsupported(superblock.compat_features);
3415 cerr << "On-disk OSD incompatible features set "
3416 << unsupported << std::endl;
3417 ret = -EINVAL;
3418 goto out;
3419 }
3420
3421 if (op == "apply-layout-settings") {
3422 int target_level = 0;
3423 // Single positional argument with apply-layout-settings
3424 // for target_level.
3425 if (vm.count("object") && isdigit(object[0])) {
3426 target_level = atoi(object.c_str());
3427 // This requires --arg1 to be specified since
3428 // this is the third positional argument and normally
3429 // used with object operations.
3430 } else if (vm.count("arg1") && isdigit(arg1[0])) {
3431 target_level = atoi(arg1.c_str());
3432 }
3433 ret = apply_layout_settings(fs, superblock, pool, pgid, dry_run, target_level);
3434 goto out;
3435 }
3436
3437 if (op != "list" && vm.count("object")) {
3438 // Special case: Create pgmeta_oid if empty string specified
3439 // This can't conflict with any actual object names.
3440 if (object == "") {
3441 ghobj = pgid.make_pgmeta_oid();
3442 } else {
3443 json_spirit::Value v;
3444 try {
3445 if (!json_spirit::read(object, v) ||
3446 (v.type() != json_spirit::array_type && v.type() != json_spirit::obj_type)) {
3447 // Special: Need head/snapdir so set even if user didn't specify
3448 if (vm.count("objcmd") && (objcmd == "remove-clone-metadata"))
3449 head = true;
3450 lookup_ghobject lookup(object, nspace, head);
3451 if (pgidstr.length())
3452 ret = action_on_all_objects_in_exact_pg(fs, coll_t(pgid), lookup, debug);
3453 else
3454 ret = action_on_all_objects(fs, lookup, debug);
3455 if (ret) {
3456 throw std::runtime_error("Internal error");
3457 } else {
3458 if (lookup.size() != 1) {
3459 stringstream ss;
3460 if (lookup.size() == 0)
3461 ss << "No object id '" << object << "' found or invalid JSON specified";
3462 else
3463 ss << "Found " << lookup.size() << " objects with id '" << object
3464 << "', please use a JSON spec from --op list instead";
3465 throw std::runtime_error(ss.str());
3466 }
3467 pair<coll_t, ghobject_t> found = lookup.pop();
3468 pgidstr = found.first.to_str();
3469 pgid.parse(pgidstr.c_str());
3470 ghobj = found.second;
3471 }
3472 } else {
3473 stringstream ss;
3474 if (pgidstr.length() == 0 && v.type() != json_spirit::array_type) {
3475 ss << "Without --pgid the object '" << object
3476 << "' must be a JSON array";
3477 throw std::runtime_error(ss.str());
3478 }
3479 if (v.type() == json_spirit::array_type) {
3480 json_spirit::Array array = v.get_array();
3481 if (array.size() != 2) {
3482 ss << "Object '" << object
3483 << "' must be a JSON array with 2 elements";
3484 throw std::runtime_error(ss.str());
3485 }
3486 vector<json_spirit::Value>::iterator i = array.begin();
3487 assert(i != array.end());
3488 if (i->type() != json_spirit::str_type) {
3489 ss << "Object '" << object
3490 << "' must be a JSON array with the first element a string";
3491 throw std::runtime_error(ss.str());
3492 }
3493 string object_pgidstr = i->get_str();
3494 if (object_pgidstr != "meta") {
3495 spg_t object_pgid;
3496 object_pgid.parse(object_pgidstr.c_str());
3497 if (pgidstr.length() > 0) {
3498 if (object_pgid != pgid) {
3499 ss << "object '" << object
3500 << "' has a pgid different from the --pgid="
3501 << pgidstr << " option";
3502 throw std::runtime_error(ss.str());
3503 }
3504 } else {
3505 pgidstr = object_pgidstr;
3506 pgid = object_pgid;
3507 }
3508 } else {
3509 pgidstr = object_pgidstr;
3510 }
3511 ++i;
3512 v = *i;
3513 }
3514 try {
3515 ghobj.decode(v);
3516 } catch (std::runtime_error& e) {
3517 ss << "Decode object JSON error: " << e.what();
3518 throw std::runtime_error(ss.str());
3519 }
3520 if (pgidstr != "meta" && (uint64_t)pgid.pgid.m_pool != (uint64_t)ghobj.hobj.pool) {
3521 cerr << "Object pool and pgid pool don't match" << std::endl;
3522 ret = 1;
3523 goto out;
3524 }
3525 }
3526 } catch (std::runtime_error& e) {
3527 cerr << e.what() << std::endl;
3528 ret = 1;
3529 goto out;
3530 }
3531 }
3532 }
3533
3534 // The ops which require --pgid option are checked here and
3535 // mentioned in the usage for --pgid.
3536 if ((op == "info" || op == "log" || op == "remove" || op == "export"
3537 || op == "export-remove" || op == "rm-past-intervals"
3538 || op == "mark-complete" || op == "trim-pg-log") &&
3539 pgidstr.length() == 0) {
3540 cerr << "Must provide pgid" << std::endl;
3541 usage(desc);
3542 ret = 1;
3543 goto out;
3544 }
3545
3546 if (op == "import") {
3547
3548 try {
3549 ret = tool.do_import(fs, superblock, force, pgidstr, *osr);
3550 }
3551 catch (const buffer::error &e) {
3552 cerr << "do_import threw exception error " << e.what() << std::endl;
3553 ret = -EFAULT;
3554 }
3555 if (ret == -EFAULT) {
3556 cerr << "Corrupt input for import" << std::endl;
3557 }
3558 if (ret == 0)
3559 cout << "Import successful" << std::endl;
3560 goto out;
3561 } else if (op == "dump-journal-mount") {
3562 // Undocumented feature to dump journal with mounted fs
3563 // This doesn't support the format option, but it uses the
3564 // ObjectStore::dump_journal() and mounts to get replay to run.
3565 ret = fs->dump_journal(cout);
3566 if (ret) {
3567 if (ret == -EOPNOTSUPP) {
3568 cerr << "Object store type \"" << type << "\" doesn't support journal dump" << std::endl;
3569 } else {
3570 cerr << "Journal dump failed with error " << cpp_strerror(ret) << std::endl;
3571 }
3572 }
3573 goto out;
3574 } else if (op == "get-osdmap") {
3575 bufferlist bl;
3576 OSDMap osdmap;
3577 if (epoch == 0) {
3578 epoch = superblock.current_epoch;
3579 }
3580 ret = get_osdmap(fs, epoch, osdmap, bl);
3581 if (ret) {
3582 cerr << "Failed to get osdmap#" << epoch << ": "
3583 << cpp_strerror(ret) << std::endl;
3584 goto out;
3585 }
3586 ret = bl.write_fd(file_fd);
3587 if (ret) {
3588 cerr << "Failed to write to " << file << ": " << cpp_strerror(ret) << std::endl;
3589 } else {
3590 cout << "osdmap#" << epoch << " exported." << std::endl;
3591 }
3592 goto out;
3593 } else if (op == "set-osdmap") {
3594 bufferlist bl;
3595 ret = get_fd_data(file_fd, bl);
3596 if (ret < 0) {
3597 cerr << "Failed to read osdmap " << cpp_strerror(ret) << std::endl;
3598 } else {
3599 ret = set_osdmap(fs, epoch, bl, force, *osr);
3600 }
3601 goto out;
3602 } else if (op == "get-inc-osdmap") {
3603 bufferlist bl;
3604 if (epoch == 0) {
3605 epoch = superblock.current_epoch;
3606 }
3607 ret = get_inc_osdmap(fs, epoch, bl);
3608 if (ret < 0) {
3609 cerr << "Failed to get incremental osdmap# " << epoch << ": "
3610 << cpp_strerror(ret) << std::endl;
3611 goto out;
3612 }
3613 ret = bl.write_fd(file_fd);
3614 if (ret) {
3615 cerr << "Failed to write to " << file << ": " << cpp_strerror(ret) << std::endl;
3616 } else {
3617 cout << "inc-osdmap#" << epoch << " exported." << std::endl;
3618 }
3619 goto out;
3620 } else if (op == "set-inc-osdmap") {
3621 bufferlist bl;
3622 ret = get_fd_data(file_fd, bl);
3623 if (ret < 0) {
3624 cerr << "Failed to read incremental osdmap " << cpp_strerror(ret) << std::endl;
3625 goto out;
3626 } else {
3627 ret = set_inc_osdmap(fs, epoch, bl, force, *osr);
3628 }
3629 goto out;
3630 } else if (op == "update-mon-db") {
3631 if (!vm.count("mon-store-path")) {
3632 cerr << "Please specify the path to monitor db to update" << std::endl;
3633 ret = -EINVAL;
3634 } else {
3635 ret = update_mon_db(*fs, superblock, dpath + "/keyring", mon_store_path);
3636 }
3637 goto out;
3638 }
3639
3640 log_oid = OSD::make_pg_log_oid(pgid);
3641 biginfo_oid = OSD::make_pg_biginfo_oid(pgid);
3642
3643 if (op == "remove") {
3644 if (!force && !dry_run) {
3645 cerr << "Please use export-remove or you must use --force option" << std::endl;
3646 ret = -EINVAL;
3647 goto out;
3648 }
3649 ret = initiate_new_remove_pg(fs, pgid, *osr);
3650 if (ret < 0) {
3651 cerr << "PG '" << pgid << "' not found" << std::endl;
3652 goto out;
3653 }
3654 cout << "Remove successful" << std::endl;
3655 goto out;
3656 }
3657
3658 if (op == "fix-lost") {
3659 boost::scoped_ptr<action_on_object_t> action;
3660 action.reset(new do_fix_lost(osr));
3661 if (pgidstr.length())
3662 ret = action_on_all_objects_in_exact_pg(fs, coll_t(pgid), *action, debug);
3663 else
3664 ret = action_on_all_objects(fs, *action, debug);
3665 goto out;
3666 }
3667
3668 if (op == "list") {
3669 ret = do_list(fs, pgidstr, object, nspace, formatter, debug,
3670 human_readable, head);
3671 if (ret < 0) {
3672 cerr << "do_list failed: " << cpp_strerror(ret) << std::endl;
3673 }
3674 goto out;
3675 }
3676
3677 if (op == "dump-super") {
3678 formatter->open_object_section("superblock");
3679 superblock.dump(formatter);
3680 formatter->close_section();
3681 formatter->flush(cout);
3682 cout << std::endl;
3683 goto out;
3684 }
3685
3686 if (op == "meta-list") {
3687 ret = do_meta(fs, object, formatter, debug, human_readable);
3688 if (ret < 0) {
3689 cerr << "do_meta failed: " << cpp_strerror(ret) << std::endl;
3690 }
3691 goto out;
3692 }
3693
3694 ret = fs->list_collections(ls);
3695 if (ret < 0) {
3696 cerr << "failed to list pgs: " << cpp_strerror(ret) << std::endl;
3697 goto out;
3698 }
3699
3700 if (debug && op == "list-pgs")
3701 cout << "Performing list-pgs operation" << std::endl;
3702
3703 // Find pg
3704 for (it = ls.begin(); it != ls.end(); ++it) {
3705 spg_t tmppgid;
3706
3707 if (pgidstr == "meta") {
3708 if (it->to_str() == "meta")
3709 break;
3710 else
3711 continue;
3712 }
3713
3714 if (!it->is_pg(&tmppgid)) {
3715 continue;
3716 }
3717
3718 if (it->is_temp(&tmppgid)) {
3719 continue;
3720 }
3721
3722 if (op != "list-pgs" && tmppgid != pgid) {
3723 continue;
3724 }
3725
3726 if (op != "list-pgs") {
3727 //Found!
3728 break;
3729 }
3730
3731 cout << tmppgid << std::endl;
3732 }
3733
3734 if (op == "list-pgs") {
3735 ret = 0;
3736 goto out;
3737 }
3738
3739 // If not an object command nor any of the ops handled below, then output this usage
3740 // before complaining about a bad pgid
3741 if (!vm.count("objcmd") && op != "export" && op != "export-remove" && op != "info" && op != "log" && op != "rm-past-intervals" && op != "mark-complete" && op != "trim-pg-log") {
3742 cerr << "Must provide --op (info, log, remove, mkfs, fsck, repair, export, export-remove, import, list, fix-lost, list-pgs, rm-past-intervals, dump-journal, dump-super, meta-list, "
3743 "get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, dump-import, trim-pg-log)"
3744 << std::endl;
3745 usage(desc);
3746 ret = 1;
3747 goto out;
3748 }
3749 epoch_t map_epoch;
3750 // The following code for export, info, log require omap or !skip-mount-omap
3751 if (it != ls.end()) {
3752
3753 coll_t coll = *it;
3754
3755 if (vm.count("objcmd")) {
3756 ret = 0;
3757 if (objcmd == "remove" || objcmd == "removeall") {
3758 bool all = (objcmd == "removeall");
3759 ret = do_remove_object(fs, coll, ghobj, all, force, *osr);
3760 goto out;
3761 } else if (objcmd == "list-attrs") {
3762 ret = do_list_attrs(fs, coll, ghobj);
3763 goto out;
3764 } else if (objcmd == "list-omap") {
3765 ret = do_list_omap(fs, coll, ghobj);
3766 goto out;
3767 } else if (objcmd == "get-bytes" || objcmd == "set-bytes") {
3768 if (objcmd == "get-bytes") {
3769 int fd;
3770 if (vm.count("arg1") == 0 || arg1 == "-") {
3771 fd = STDOUT_FILENO;
3772 } else {
3773 fd = open(arg1.c_str(), O_WRONLY|O_TRUNC|O_CREAT|O_EXCL|O_LARGEFILE, 0666);
3774 if (fd == -1) {
3775 cerr << "open " << arg1 << " " << cpp_strerror(errno) << std::endl;
3776 ret = 1;
3777 goto out;
3778 }
3779 }
3780 ret = do_get_bytes(fs, coll, ghobj, fd);
3781 if (fd != STDOUT_FILENO)
3782 close(fd);
3783 } else {
3784 int fd;
3785 if (vm.count("arg1") == 0 || arg1 == "-") {
3786 // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it.
3787 if (isatty(STDIN_FILENO)) {
3788 cerr << "stdin is a tty and no file specified" << std::endl;
3789 ret = 1;
3790 goto out;
3791 }
3792 fd = STDIN_FILENO;
3793 } else {
3794 fd = open(arg1.c_str(), O_RDONLY|O_LARGEFILE, 0666);
3795 if (fd == -1) {
3796 cerr << "open " << arg1 << " " << cpp_strerror(errno) << std::endl;
3797 ret = 1;
3798 goto out;
3799 }
3800 }
3801 ret = do_set_bytes(fs, coll, ghobj, fd, *osr);
3802 if (fd != STDIN_FILENO)
3803 close(fd);
3804 }
3805 goto out;
3806 } else if (objcmd == "get-attr") {
3807 if (vm.count("arg1") == 0) {
3808 usage(desc);
3809 ret = 1;
3810 goto out;
3811 }
3812 ret = do_get_attr(fs, coll, ghobj, arg1);
3813 goto out;
3814 } else if (objcmd == "set-attr") {
3815 if (vm.count("arg1") == 0) {
3816 usage(desc);
3817 ret = 1;
3818 }
3819
3820 int fd;
3821 if (vm.count("arg2") == 0 || arg2 == "-") {
3822 // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it.
3823 if (isatty(STDIN_FILENO)) {
3824 cerr << "stdin is a tty and no file specified" << std::endl;
3825 ret = 1;
3826 goto out;
3827 }
3828 fd = STDIN_FILENO;
3829 } else {
3830 fd = open(arg2.c_str(), O_RDONLY|O_LARGEFILE, 0666);
3831 if (fd == -1) {
3832 cerr << "open " << arg2 << " " << cpp_strerror(errno) << std::endl;
3833 ret = 1;
3834 goto out;
3835 }
3836 }
3837 ret = do_set_attr(fs, coll, ghobj, arg1, fd, *osr);
3838 if (fd != STDIN_FILENO)
3839 close(fd);
3840 goto out;
3841 } else if (objcmd == "rm-attr") {
3842 if (vm.count("arg1") == 0) {
3843 usage(desc);
3844 ret = 1;
3845 goto out;
3846 }
3847 ret = do_rm_attr(fs, coll, ghobj, arg1, *osr);
3848 goto out;
3849 } else if (objcmd == "get-omap") {
3850 if (vm.count("arg1") == 0) {
3851 usage(desc);
3852 ret = 1;
3853 goto out;
3854 }
3855 ret = do_get_omap(fs, coll, ghobj, arg1);
3856 goto out;
3857 } else if (objcmd == "set-omap") {
3858 if (vm.count("arg1") == 0) {
3859 usage(desc);
3860 ret = 1;
3861 goto out;
3862 }
3863 int fd;
3864 if (vm.count("arg2") == 0 || arg2 == "-") {
3865 // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it.
3866 if (isatty(STDIN_FILENO)) {
3867 cerr << "stdin is a tty and no file specified" << std::endl;
3868 ret = 1;
3869 goto out;
3870 }
3871 fd = STDIN_FILENO;
3872 } else {
3873 fd = open(arg2.c_str(), O_RDONLY|O_LARGEFILE, 0666);
3874 if (fd == -1) {
3875 cerr << "open " << arg2 << " " << cpp_strerror(errno) << std::endl;
3876 ret = 1;
3877 goto out;
3878 }
3879 }
3880 ret = do_set_omap(fs, coll, ghobj, arg1, fd, *osr);
3881 if (fd != STDIN_FILENO)
3882 close(fd);
3883 goto out;
3884 } else if (objcmd == "rm-omap") {
3885 if (vm.count("arg1") == 0) {
3886 usage(desc);
3887 ret = 1;
3888 goto out;
3889 }
3890 ret = do_rm_omap(fs, coll, ghobj, arg1, *osr);
3891 goto out;
3892 } else if (objcmd == "get-omaphdr") {
3893 if (vm.count("arg1")) {
3894 usage(desc);
3895 ret = 1;
3896 goto out;
3897 }
3898 ret = do_get_omaphdr(fs, coll, ghobj);
3899 goto out;
3900 } else if (objcmd == "set-omaphdr") {
3901 // Extra arg
3902 if (vm.count("arg2")) {
3903 usage(desc);
3904 ret = 1;
3905 goto out;
3906 }
3907 int fd;
3908 if (vm.count("arg1") == 0 || arg1 == "-") {
3909 // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it.
3910 if (isatty(STDIN_FILENO)) {
3911 cerr << "stdin is a tty and no file specified" << std::endl;
3912 ret = 1;
3913 goto out;
3914 }
3915 fd = STDIN_FILENO;
3916 } else {
3917 fd = open(arg1.c_str(), O_RDONLY|O_LARGEFILE, 0666);
3918 if (fd == -1) {
3919 cerr << "open " << arg1 << " " << cpp_strerror(errno) << std::endl;
3920 ret = 1;
3921 goto out;
3922 }
3923 }
3924 ret = do_set_omaphdr(fs, coll, ghobj, fd, *osr);
3925 if (fd != STDIN_FILENO)
3926 close(fd);
3927 goto out;
3928 } else if (objcmd == "dump") {
3929 // There should not be any other arguments
3930 if (vm.count("arg1") || vm.count("arg2")) {
3931 usage(desc);
3932 ret = 1;
3933 goto out;
3934 }
3935 ret = print_obj_info(fs, coll, ghobj, formatter);
3936 goto out;
3937 } else if (objcmd == "corrupt-info") { // Undocumented testing feature
3938 // There should not be any other arguments
3939 if (vm.count("arg1") || vm.count("arg2")) {
3940 usage(desc);
3941 ret = 1;
3942 goto out;
3943 }
3944 ret = corrupt_info(fs, coll, ghobj, formatter, *osr);
3945 goto out;
3946 } else if (objcmd == "set-size" || objcmd == "corrupt-size") {
3947 // Undocumented testing feature
3948 bool corrupt = (objcmd == "corrupt-size");
3949 // Extra arg
3950 if (vm.count("arg1") == 0 || vm.count("arg2")) {
3951 usage(desc);
3952 ret = 1;
3953 goto out;
3954 }
3955 if (arg1.length() == 0 || !isdigit(arg1.c_str()[0])) {
3956 cerr << "Invalid size '" << arg1 << "' specified" << std::endl;
3957 ret = 1;
3958 goto out;
3959 }
3960 uint64_t size = atoll(arg1.c_str());
3961 ret = set_size(fs, coll, ghobj, size, formatter, *osr, corrupt);
3962 goto out;
3963 } else if (objcmd == "clear-snapset") {
3964 // UNDOCUMENTED: For testing zap SnapSet
3965 // IGNORE extra args since not in usage anyway
3966 if (!ghobj.hobj.has_snapset()) {
3967 cerr << "'" << objcmd << "' requires a head or snapdir object" << std::endl;
3968 ret = 1;
3969 goto out;
3970 }
3971 ret = clear_snapset(fs, coll, ghobj, arg1, *osr);
3972 goto out;
3973 } else if (objcmd == "remove-clone-metadata") {
3974 // Extra arg
3975 if (vm.count("arg1") == 0 || vm.count("arg2")) {
3976 usage(desc);
3977 ret = 1;
3978 goto out;
3979 }
3980 if (!ghobj.hobj.has_snapset()) {
3981 cerr << "'" << objcmd << "' requires a head or snapdir object" << std::endl;
3982 ret = 1;
3983 goto out;
3984 }
3985 if (arg1.length() == 0 || !isdigit(arg1.c_str()[0])) {
3986 cerr << "Invalid cloneid '" << arg1 << "' specified" << std::endl;
3987 ret = 1;
3988 goto out;
3989 }
3990 snapid_t cloneid = atoi(arg1.c_str());
3991 ret = remove_clone(fs, coll, ghobj, cloneid, force, *osr);
3992 goto out;
3993 }
3994 cerr << "Unknown object command '" << objcmd << "'" << std::endl;
3995 usage(desc);
3996 ret = 1;
3997 goto out;
3998 }
3999
4000 bufferlist bl;
4001 map_epoch = 0;
4002 ret = PG::peek_map_epoch(fs, pgid, &map_epoch, &bl);
4003 if (ret < 0)
4004 cerr << "peek_map_epoch reports error" << std::endl;
4005 if (debug)
4006 cerr << "map_epoch " << map_epoch << std::endl;
4007
4008 pg_info_t info(pgid);
4009 PastIntervals past_intervals;
4010 __u8 struct_ver;
4011 ret = PG::read_info(fs, pgid, coll, bl, info, past_intervals,
4012 struct_ver);
4013 if (ret < 0) {
4014 cerr << "read_info error " << cpp_strerror(ret) << std::endl;
4015 goto out;
4016 }
4017 if (struct_ver < PG::compat_struct_v) {
4018 cerr << "PG is too old to upgrade, use older Ceph version" << std::endl;
4019 ret = -EFAULT;
4020 goto out;
4021 }
4022 if (debug)
4023 cerr << "struct_v " << (int)struct_ver << std::endl;
4024
4025 if (op == "export" || op == "export-remove") {
4026 ret = tool.do_export(fs, coll, pgid, info, map_epoch, struct_ver, superblock, past_intervals);
4027 if (ret == 0) {
4028 cerr << "Export successful" << std::endl;
4029 if (op == "export-remove") {
4030 ret = initiate_new_remove_pg(fs, pgid, *osr);
4031 // Export succeeded, so pgid is there
4032 assert(ret == 0);
4033 cerr << "Remove successful" << std::endl;
4034 }
4035 }
4036 } else if (op == "info") {
4037 formatter->open_object_section("info");
4038 info.dump(formatter);
4039 formatter->close_section();
4040 formatter->flush(cout);
4041 cout << std::endl;
4042 } else if (op == "log") {
4043 PGLog::IndexedLog log;
4044 pg_missing_t missing;
4045 ret = get_log(fs, struct_ver, coll, pgid, info, log, missing);
4046 if (ret < 0)
4047 goto out;
4048
4049 dump_log(formatter, cout, log, missing);
4050 } else if (op == "rm-past-intervals") {
4051 ObjectStore::Transaction tran;
4052 ObjectStore::Transaction *t = &tran;
4053
4054 if (struct_ver < PG::compat_struct_v) {
4055 cerr << "Can't remove past-intervals, version mismatch " << (int)struct_ver
4056 << " (pg) < compat " << (int)PG::compat_struct_v << " (tool)"
4057 << std::endl;
4058 ret = -EFAULT;
4059 goto out;
4060 }
4061
4062 cout << "Remove past-intervals " << past_intervals << std::endl;
4063
4064 past_intervals.clear();
4065 if (dry_run) {
4066 ret = 0;
4067 goto out;
4068 }
4069 ret = write_info(*t, map_epoch, info, past_intervals);
4070
4071 if (ret == 0) {
4072 fs->apply_transaction(osr, std::move(*t));
4073 cout << "Removal succeeded" << std::endl;
4074 }
4075 } else if (op == "mark-complete") {
4076 ObjectStore::Transaction tran;
4077 ObjectStore::Transaction *t = &tran;
4078
4079 if (struct_ver < PG::compat_struct_v) {
4080 cerr << "Can't mark-complete, version mismatch " << (int)struct_ver
4081 << " (pg) < compat " << (int)PG::compat_struct_v << " (tool)"
4082 << std::endl;
4083 ret = 1;
4084 goto out;
4085 }
4086
4087 cout << "Marking complete " << std::endl;
4088
4089 info.last_update = eversion_t(superblock.current_epoch, info.last_update.version + 1);
4090 info.last_backfill = hobject_t::get_max();
4091 info.last_epoch_started = superblock.current_epoch;
4092 info.history.last_epoch_started = superblock.current_epoch;
4093 info.history.last_epoch_clean = superblock.current_epoch;
4094 past_intervals.clear();
4095
4096 if (!dry_run) {
4097 ret = write_info(*t, map_epoch, info, past_intervals);
4098 if (ret != 0)
4099 goto out;
4100 fs->apply_transaction(osr, std::move(*t));
4101 }
4102 cout << "Marking complete succeeded" << std::endl;
4103 } else if (op == "trim-pg-log") {
4104 ret = do_trim_pg_log(fs, coll, info, pgid, *osr,
4105 map_epoch, past_intervals);
4106 if (ret < 0) {
4107 cerr << "Error trimming pg log: " << cpp_strerror(ret) << std::endl;
4108 goto out;
4109 }
4110 cout << "Finished trimming pg log" << std::endl;
4111 goto out;
4112 } else {
4113 assert(!"Should have already checked for valid --op");
4114 }
4115 } else {
4116 cerr << "PG '" << pgid << "' not found" << std::endl;
4117 ret = -ENOENT;
4118 }
4119
4120 out:
4121 int r = fs->umount();
4122 delete osr;
4123 if (r < 0) {
4124 cerr << "umount failed: " << cpp_strerror(r) << std::endl;
4125 // If no previous error, then use umount() error
4126 if (ret == 0)
4127 ret = r;
4128 }
4129
4130 if (dry_run) {
4131 // Export output can go to stdout, so put this message on stderr
4132 if (op == "export")
4133 cerr << "dry-run: Nothing changed" << std::endl;
4134 else
4135 cout << "dry-run: Nothing changed" << std::endl;
4136 }
4137
4138 if (ret < 0)
4139 ret = 1;
4140 return ret;
4141 }