]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rados/rados.cc
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / tools / rados / rados.cc
CommitLineData
7c673cae
FG
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) 2004-2006 Sage Weil <sage@newdream.net>
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 "include/types.h"
16
11fdf7f2 17#include "include/rados/buffer.h"
7c673cae
FG
18#include "include/rados/librados.hpp"
19#include "include/rados/rados_types.hpp"
11fdf7f2
TL
20
21#include "acconfig.h"
22#ifdef WITH_LIBRADOSSTRIPER
23 #include "include/radosstriper/libradosstriper.hpp"
24 using namespace libradosstriper;
25#endif
7c673cae
FG
26
27#include "common/config.h"
28#include "common/ceph_argparse.h"
29#include "global/global_init.h"
30#include "common/Cond.h"
31#include "common/debug.h"
32#include "common/errno.h"
33#include "common/Formatter.h"
34#include "common/obj_bencher.h"
35#include "common/TextTable.h"
36#include "include/stringify.h"
37#include "mds/inode_backtrace.h"
11fdf7f2 38#include "include/random.h"
7c673cae
FG
39#include <iostream>
40#include <fstream>
41
42#include <stdlib.h>
43#include <time.h>
44#include <sstream>
45#include <errno.h>
46#include <dirent.h>
47#include <stdexcept>
48#include <climits>
49#include <locale>
50#include <memory>
f67539c2 51#include <optional>
7c673cae
FG
52
53#include "cls/lock/cls_lock_client.h"
54#include "include/compat.h"
55#include "include/util.h"
56#include "common/hobject.h"
57
58#include "PoolDump.h"
59#include "RadosImport.h"
60
94b18763
FG
61#include "osd/ECUtil.h"
62
20effc67 63using namespace std::chrono_literals;
7c673cae 64using namespace librados;
11fdf7f2 65using ceph::util::generate_random_number;
20effc67
TL
66using std::cerr;
67using std::cout;
68using std::dec;
69using std::hex;
70using std::less;
71using std::list;
72using std::map;
73using std::multiset;
74using std::ofstream;
75using std::ostream;
76using std::pair;
77using std::set;
78using std::string;
79using std::unique_ptr;
80using std::vector;
7c673cae
FG
81
82// two steps seem to be necessary to do this right
83#define STR(x) _STR(x)
84#define _STR(x) #x
85
86void usage(ostream& out)
87{
88 out << \
89"usage: rados [options] [commands]\n"
90"POOL COMMANDS\n"
91" lspools list pools\n"
7c673cae 92" cppool <pool-name> <dest-pool> copy content of a pool\n"
7c673cae 93" purge <pool-name> --yes-i-really-really-mean-it\n"
aee94f69 94" remove all objects from pool <pool-name> without removing the pool itself\n"
7c673cae
FG
95" df show per-pool and total usage\n"
96" ls list objects in pool\n\n"
7c673cae
FG
97"\n"
98"POOL SNAP COMMANDS\n"
99" lssnap list snaps\n"
100" mksnap <snap-name> create snap <snap-name>\n"
101" rmsnap <snap-name> remove snap <snap-name>\n"
102"\n"
103"OBJECT COMMANDS\n"
11fdf7f2
TL
104" get <obj-name> <outfile> fetch object\n"
105" put <obj-name> <infile> [--offset offset]\n"
31f18b77 106" write object with start offset (default:0)\n"
11fdf7f2 107" append <obj-name> <infile> append object\n"
7c673cae
FG
108" truncate <obj-name> length truncate object\n"
109" create <obj-name> create object\n"
20effc67 110" rm <obj-name> ... [--force-full] remove object(s), --force-full forces remove when cluster is full\n"
7c673cae 111" cp <obj-name> [target-obj] copy object\n"
20effc67
TL
112" listxattr <obj-name> list attrs of this object\n"
113" getxattr <obj-name> <attr> get the <attr> attribute of this object\n"
7c673cae
FG
114" setxattr <obj-name> attr val\n"
115" rmxattr <obj-name> attr\n"
35e4c445 116" stat <obj-name> stat the named object\n"
11fdf7f2
TL
117" stat2 <obj-name> stat2 the named object (with high precision time)\n"
118" touch <obj-name> [timestamp] change the named object modification time\n"
7c673cae
FG
119" mapext <obj-name>\n"
120" rollback <obj-name> <snap-name> roll back object to snap <snap-name>\n"
121"\n"
122" listsnaps <obj-name> list the snapshots of this object\n"
11fdf7f2 123" bench <seconds> write|seq|rand [-t concurrent_operations] [--no-cleanup] [--run-name run_name] [--no-hints] [--reuse-bench]\n"
7c673cae
FG
124" default is 16 concurrent IOs and 4 MB ops\n"
125" default is to clean up after write benchmark\n"
126" default run-name is 'benchmark_last_metadata'\n"
127" cleanup [--run-name run_name] [--prefix prefix]\n"
128" clean up a previous benchmark operation\n"
129" default run-name is 'benchmark_last_metadata'\n"
130" load-gen [options] generate load on the cluster\n"
131" listomapkeys <obj-name> list the keys in the object map\n"
132" listomapvals <obj-name> list the keys and vals in the object map \n"
133" getomapval <obj-name> <key> [file] show the value for the specified key\n"
134" in the object's object map\n"
f67539c2 135" setomapval <obj-name> <key> <val | --input-file file>\n"
20effc67 136" rmomapkey <obj-name> <key> Remove key from the object map of <obj-name>\n"
11fdf7f2 137" clearomap <obj-name> [obj-name2 obj-name3...] clear all the omap keys for the specified objects\n"
20effc67
TL
138" getomapheader <obj-name> [file] Dump the hexadecimal value of the object map header of <obj-name>\n"
139" setomapheader <obj-name> <val> Set the value of the object map header of <obj-name>\n"
7c673cae
FG
140" watch <obj-name> add watcher on this object\n"
141" notify <obj-name> <message> notify watcher of this object with message\n"
142" listwatchers <obj-name> list the watchers of this object\n"
143" set-alloc-hint <obj-name> <expected-object-size> <expected-write-size>\n"
144" set allocation hint for an object\n"
11fdf7f2
TL
145" set-redirect <object A> --target-pool <caspool> <target object A> [--with-reference]\n"
146" set redirect target\n"
147" set-chunk <object A> <offset> <length> --target-pool <caspool> <target object A> <taget-offset> [--with-reference]\n"
148" convert an object to chunked object\n"
149" tier-promote <obj-name> promote the object to the base tier\n"
150" unset-manifest <obj-name> unset redirect or chunked object\n"
9f95a23c 151" tier-flush <obj-name> flush the chunked object\n"
f67539c2 152" tier-evict <obj-name> evict the chunked object\n"
7c673cae
FG
153"\n"
154"IMPORT AND EXPORT\n"
155" export [filename]\n"
156" Serialize pool contents to a file or standard out.\n"
157" import [--dry-run] [--no-overwrite] < filename | - >\n"
158" Load pool contents from a file or standard in\n"
159"\n"
160"ADVISORY LOCKS\n"
161" lock list <obj-name>\n"
162" List all advisory locks on an object\n"
9f95a23c 163" lock get <obj-name> <lock-name> [--lock-cookie locker-cookie] [--lock-tag locker-tag] [--lock-description locker-desc] [--lock-duration locker-dur] [--lock-type locker-type]\n"
7c673cae 164" Try to acquire a lock\n"
9f95a23c 165" lock break <obj-name> <lock-name> <locker-name> [--lock-cookie locker-cookie]\n"
7c673cae
FG
166" Try to break a lock acquired by another client\n"
167" lock info <obj-name> <lock-name>\n"
168" Show lock information\n"
169" options:\n"
170" --lock-tag Lock tag, all locks operation should use\n"
171" the same tag\n"
172" --lock-cookie Locker cookie\n"
173" --lock-description Description of lock\n"
174" --lock-duration Lock duration (in seconds)\n"
175" --lock-type Lock type (shared, exclusive)\n"
176"\n"
177"SCRUB AND REPAIR:\n"
178" list-inconsistent-pg <pool> list inconsistent PGs in given pool\n"
eafe8130
TL
179" list-inconsistent-obj <pgid> list inconsistent objects in given PG\n"
180" list-inconsistent-snapset <pgid> list inconsistent snapsets in the given PG\n"
7c673cae
FG
181"\n"
182"CACHE POOLS: (for testing/development only)\n"
183" cache-flush <obj-name> flush cache pool object (blocking)\n"
184" cache-try-flush <obj-name> flush cache pool object (non-blocking)\n"
185" cache-evict <obj-name> evict cache pool object\n"
186" cache-flush-evict-all flush+evict all objects\n"
187" cache-try-flush-evict-all try-flush+evict all objects\n"
188"\n"
189"GLOBAL OPTIONS:\n"
f67539c2 190" --object-locator object_locator\n"
7c673cae
FG
191" set object_locator for operation\n"
192" -p pool\n"
193" --pool=pool\n"
194" select given pool by name\n"
195" --target-pool=pool\n"
196" select target pool by name\n"
eafe8130
TL
197" --pgid PG id\n"
198" select given PG id\n"
11fdf7f2
TL
199" -f [--format plain|json|json-pretty]\n"
200" --format=[--format plain|json|json-pretty]\n"
7c673cae
FG
201" -b op_size\n"
202" set the block size for put/get ops and for write benchmarking\n"
9f95a23c 203" -O object_size\n"
7c673cae
FG
204" set the object size for put/get ops and for write benchmarking\n"
205" --max-objects\n"
206" set the max number of objects for write benchmarking\n"
f67539c2
TL
207" --obj-name-file file\n"
208" use the content of the specified file in place of <obj-name>\n"
7c673cae
FG
209" -s name\n"
210" --snap name\n"
211" select given snap name for (read) IO\n"
f67539c2
TL
212" --input-file file\n"
213" use the content of the specified file in place of <val>\n"
7c673cae
FG
214" --create\n"
215" create the pool or directory that was specified\n"
216" -N namespace\n"
217" --namespace=namespace\n"
218" specify the namespace to use for the object\n"
219" --all\n"
220" Use with ls to list objects in all namespaces\n"
221" Put in CEPH_ARGS environment variable to make this the default\n"
222" --default\n"
223" Use with ls to list objects in default namespace\n"
224" Takes precedence over --all in case --all is in environment\n"
225" --target-locator\n"
226" Use with cp to specify the locator of the new object\n"
227" --target-nspace\n"
228" Use with cp to specify the namespace of the new object\n"
11fdf7f2 229#ifdef WITH_LIBRADOSSTRIPER
7c673cae
FG
230" --striper\n"
231" Use radostriper interface rather than pure rados\n"
232" Available for stat, get, put, truncate, rm, ls and \n"
233" all xattr related operations\n"
11fdf7f2 234#endif
7c673cae
FG
235"\n"
236"BENCH OPTIONS:\n"
237" -t N\n"
238" --concurrent-ios=N\n"
239" Set number of concurrent I/O operations\n"
240" --show-time\n"
241" prefix output with date/time\n"
242" --no-verify\n"
243" do not verify contents of read objects\n"
244" --write-object\n"
245" write contents to the objects\n"
246" --write-omap\n"
247" write contents to the omap\n"
248" --write-xattr\n"
249" write contents to the extended attributes\n"
250"\n"
251"LOAD GEN OPTIONS:\n"
252" --num-objects total number of objects\n"
253" --min-object-size min object size\n"
254" --max-object-size max object size\n"
255" --min-op-len min io size of operations\n"
256" --max-op-len max io size of operations\n"
257" --max-ops max number of operations\n"
258" --max-backlog max backlog size\n"
259" --read-percent percent of operations that are read\n"
260" --target-throughput target throughput (in bytes)\n"
261" --run-length total time (in seconds)\n"
f67539c2
TL
262" --offset-align at what boundary to align random op offsets\n"
263"\n"
7c673cae
FG
264"CACHE POOLS OPTIONS:\n"
265" --with-clones include clones when doing flush or evict\n"
f67539c2 266"\n"
7c673cae 267"OMAP OPTIONS:\n"
f67539c2
TL
268" --omap-key-file file read the omap key from a file\n"
269"\n"
270"GENERIC OPTIONS:\n";
271 generic_client_usage();
7c673cae
FG
272}
273
11fdf7f2
TL
274namespace detail {
275
276#ifdef WITH_LIBRADOSSTRIPER
277RadosStriper& striper()
278{
279 static RadosStriper s;
280 return s;
281}
282#endif
283
284int read([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, buffer::list& out_data, const unsigned op_size, const uint64_t offset, [[maybe_unused]] const bool use_striper)
285{
286#ifdef WITH_LIBRADOSSTRIPER
287 if (use_striper)
288 return striper().read(oid, &out_data, op_size, offset);
289#endif
290
291 return io_ctx.read(oid, out_data, op_size, offset);
292}
293
294int write([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, buffer::list& indata, const uint64_t count, const uint64_t offset, [[maybe_unused]] const bool use_striper)
295{
296 #ifdef WITH_LIBRADOSSTRIPER
297 if (use_striper)
298 return striper().write(oid, indata, count, offset);
299#endif
300
301 return io_ctx.write(oid, indata, count, offset);
302}
303
304int write_full([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, bufferlist& indata, [[maybe_unused]] const bool use_striper)
305{
306#ifdef WITH_LIBRADOSSTRIPER
307 if (use_striper)
308 return striper().write_full(oid, indata);
309#endif
310
311 return io_ctx.write_full(oid, indata);
312}
313
314int trunc([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const uint64_t offset, [[maybe_unused]] const bool use_striper)
315{
316#ifdef WITH_LIBRADOSSTRIPER
317 if (use_striper)
318 return striper().trunc(oid, offset);
319#endif
320
321 return io_ctx.trunc(oid, offset);
322}
323
324int append([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, buffer::list& indata, const uint64_t count, [[maybe_unused]] const bool use_striper)
325{
326#ifdef WITH_LIBRADOSSTRIPER
327 if (use_striper)
328 return striper().append(oid, indata, count);
329#endif
330
331 return io_ctx.append(oid, indata, count);
332}
333
334int setxattr([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const std::string& attr_name, buffer::list& bl, [[maybe_unused]] const bool use_striper)
335{
336#ifdef WITH_LIBRADOSSTRIPER
337 if (use_striper)
338 return striper().setxattr(oid, attr_name.c_str(), bl);
339#endif
340
341 return io_ctx.setxattr(oid, attr_name.c_str(), bl);
342}
343
344int getxattr([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const std::string& attr_name, buffer::list& bl, [[maybe_unused]] const bool use_striper)
345{
346#ifdef WITH_LIBRADOSSTRIPER
347 if (use_striper)
348 return striper().getxattr(oid, attr_name.c_str(), bl);
349#endif
350
351 return io_ctx.getxattr(oid, attr_name.c_str(), bl);
352}
353
354int rmxattr([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const std::string& attr_name, [[maybe_unused]] const bool use_striper)
355{
356#ifdef WITH_LIBRADOSSTRIPER
357 if (use_striper)
358 return striper().rmxattr(oid, attr_name.c_str());
359#endif
360
361 return io_ctx.rmxattr(oid, attr_name.c_str());
362}
363
364int getxattrs([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, std::map<std::string, buffer::list>& attrset, [[maybe_unused]] const bool use_striper)
365{
366#ifdef WITH_LIBRADOSSTRIPER
367 if (use_striper)
368 return striper().getxattrs(oid, attrset);
369#endif
370
371 return io_ctx.getxattrs(oid, attrset);
372}
373
374int remove([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const int flags, [[maybe_unused]] const bool use_striper)
375{
376#ifdef WITH_LIBRADOSSTRIPER
377 if (use_striper)
378 return striper().remove(oid, flags);
379#endif
380
381 return io_ctx.remove(oid, flags);
382}
383
384int remove([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, [[maybe_unused]] const bool use_striper)
385{
386#ifdef WITH_LIBRADOSSTRIPER
387 if (use_striper)
388 return striper().remove(oid);
389#endif
390
391 return io_ctx.remove(oid);
392}
393
394std::string get_oid(librados::NObjectIterator& i, [[maybe_unused]] const bool use_striper)
395{
396#ifdef WITH_LIBRADOSSTRIPER
397 if (use_striper)
398 return i->get_oid().substr(0, i->get_oid().length()-17);
399#endif
400
401 return i->get_oid();
402}
403
404int stat([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, uint64_t& size, time_t& mtime, [[maybe_unused]] const bool use_striper)
405{
406#ifdef WITH_LIBRADOSSTRIPER
407 if (use_striper)
408 return striper().stat(oid, &size, &mtime);
409#endif
410
411 return io_ctx.stat(oid, &size, &mtime);
412}
413
414int stat2([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, uint64_t& size, timespec& mtime, [[maybe_unused]] const bool use_striper)
415{
416#ifdef WITH_LIBRADOSSTRIPER
417 if (use_striper)
418 return striper().stat2(oid, &size, &mtime);
419#endif
420
421 return io_ctx.stat2(oid, &size, &mtime);
422}
423
424void dump_name(Formatter *formatter, const librados::NObjectIterator& i, [[maybe_unused]] const bool use_striper)
425{
426#ifdef WITH_LIBRADOSSTRIPER
427 if (use_striper) {
428 formatter->dump_string("name", i->get_oid().substr(0, i->get_oid().length()-17));
429 return;
430 }
431#endif
432
433 formatter->dump_string("name", i->get_oid());
434}
435
436} // namespace detail
437
7c673cae 438unsigned default_op_size = 1 << 22;
9f95a23c 439static const unsigned MAX_OMAP_BYTES_PER_REQUEST = 1 << 10;
7c673cae 440
11fdf7f2 441[[noreturn]] static void usage_exit()
7c673cae
FG
442{
443 usage(cerr);
444 exit(1);
445}
446
447
448template <typename I, typename T>
449static int rados_sistrtoll(I &i, T *val) {
450 std::string err;
1adf2230 451 *val = strict_iecstrtoll(i->second.c_str(), &err);
7c673cae
FG
452 if (err != "") {
453 cerr << "Invalid value for " << i->first << ": " << err << std::endl;
454 return -EINVAL;
455 } else {
456 return 0;
457 }
458}
459
460
461static int dump_data(std::string const &filename, bufferlist const &data)
462{
463 int fd;
464 if (filename == "-") {
465 fd = STDOUT_FILENO;
466 } else {
f67539c2 467 fd = TEMP_FAILURE_RETRY(::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644));
7c673cae
FG
468 if (fd < 0) {
469 int err = errno;
470 cerr << "failed to open file: " << cpp_strerror(err) << std::endl;
471 return -err;
472 }
473 }
474
475 int r = data.write_fd(fd);
476
477 if (fd != 1) {
478 VOID_TEMP_FAILURE_RETRY(::close(fd));
479 }
480
481 return r;
482}
483
484
f67539c2 485static int do_get(IoCtx& io_ctx, const std::string& oid, const char *outfile, unsigned op_size, [[maybe_unused]] const bool use_striper)
7c673cae 486{
7c673cae
FG
487 int fd;
488 if (strcmp(outfile, "-") == 0) {
489 fd = STDOUT_FILENO;
490 } else {
f67539c2 491 fd = TEMP_FAILURE_RETRY(::open(outfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644));
7c673cae
FG
492 if (fd < 0) {
493 int err = errno;
494 cerr << "failed to open file: " << cpp_strerror(err) << std::endl;
495 return -err;
496 }
497 }
498
499 uint64_t offset = 0;
500 int ret;
501 while (true) {
502 bufferlist outdata;
11fdf7f2
TL
503
504 ret = detail::read(io_ctx, oid, outdata, op_size, offset, use_striper);
7c673cae
FG
505 if (ret <= 0) {
506 goto out;
507 }
508 ret = outdata.write_fd(fd);
509 if (ret < 0) {
510 cerr << "error writing to file: " << cpp_strerror(ret) << std::endl;
511 goto out;
512 }
513 if (outdata.length() < op_size)
514 break;
515 offset += outdata.length();
516 }
517 ret = 0;
518
519 out:
520 if (fd != 1)
521 VOID_TEMP_FAILURE_RETRY(::close(fd));
522 return ret;
523}
524
525static int do_copy(IoCtx& io_ctx, const char *objname,
526 IoCtx& target_ctx, const char *target_obj)
527{
9f95a23c
TL
528 uint32_t src_fadvise_flags = LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL | LIBRADOS_OP_FLAG_FADVISE_NOCACHE;
529 uint32_t dest_fadvise_flags = LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL | LIBRADOS_OP_FLAG_FADVISE_DONTNEED;
7c673cae 530 ObjectWriteOperation op;
11fdf7f2 531 op.copy_from(objname, io_ctx, 0, src_fadvise_flags);
7c673cae
FG
532 op.set_op_flags2(dest_fadvise_flags);
533
534 return target_ctx.operate(target_obj, &op);
535}
536
537static int do_copy_pool(Rados& rados, const char *src_pool, const char *target_pool)
538{
539 IoCtx src_ctx, target_ctx;
540 int ret = rados.ioctx_create(src_pool, src_ctx);
541 if (ret < 0) {
542 cerr << "cannot open source pool: " << src_pool << std::endl;
543 return ret;
544 }
545 ret = rados.ioctx_create(target_pool, target_ctx);
546 if (ret < 0) {
547 cerr << "cannot open target pool: " << target_pool << std::endl;
548 return ret;
549 }
550 src_ctx.set_namespace(all_nspaces);
551 librados::NObjectIterator i = src_ctx.nobjects_begin();
552 librados::NObjectIterator i_end = src_ctx.nobjects_end();
553 for (; i != i_end; ++i) {
554 string nspace = i->get_nspace();
555 string oid = i->get_oid();
556 string locator = i->get_locator();
557
558 string target_name = (nspace.size() ? nspace + "/" : "") + oid;
559 string src_name = target_name;
560 if (locator.size())
561 src_name += "(@" + locator + ")";
562 cout << src_pool << ":" << src_name << " => "
563 << target_pool << ":" << target_name << std::endl;
564
565 src_ctx.locator_set_key(locator);
566 src_ctx.set_namespace(nspace);
567 target_ctx.set_namespace(nspace);
568 ret = do_copy(src_ctx, oid.c_str(), target_ctx, oid.c_str());
569 if (ret < 0) {
570 cerr << "error copying object: " << cpp_strerror(errno) << std::endl;
571 return ret;
572 }
573 }
574
575 return 0;
576}
577
11fdf7f2 578static int do_put(IoCtx& io_ctx,
f67539c2 579 const std::string& oid, const char *infile, int op_size,
9f95a23c 580 uint64_t obj_offset, bool create_object,
11fdf7f2 581 const bool use_striper)
7c673cae 582{
7c673cae
FG
583 bool stdio = (strcmp(infile, "-") == 0);
584 int ret = 0;
585 int fd = STDIN_FILENO;
586 if (!stdio)
f67539c2 587 fd = open(infile, O_RDONLY|O_BINARY);
7c673cae
FG
588 if (fd < 0) {
589 cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl;
590 return 1;
591 }
592 int count = op_size;
593 uint64_t offset = obj_offset;
594 while (count != 0) {
595 bufferlist indata;
596 count = indata.read_fd(fd, op_size);
597 if (count < 0) {
598 ret = -errno;
599 cerr << "error reading input file " << infile << ": " << cpp_strerror(ret) << std::endl;
600 goto out;
601 }
602
603 if (count == 0) {
604 if (offset == obj_offset) { // in case we have to create an empty object & if obj_offset > 0 do a hole
11fdf7f2 605 ret = detail::write_full(io_ctx, oid, indata, use_striper); // indata is empty
7c673cae 606
11fdf7f2
TL
607 if (ret < 0) {
608 goto out;
609 }
610
611 if (offset) {
612 ret = detail::trunc(io_ctx, oid, offset, use_striper); // before truncate, object must be existed.
613
614 if (ret < 0) {
615 goto out;
616 }
617 }
7c673cae 618 }
11fdf7f2 619 continue;
7c673cae
FG
620 }
621
9f95a23c 622 if (0 == offset && create_object)
11fdf7f2
TL
623 ret = detail::write_full(io_ctx, oid, indata, use_striper);
624 else
625 ret = detail::write(io_ctx, oid, indata, count, offset, use_striper);
626
7c673cae
FG
627 if (ret < 0) {
628 goto out;
629 }
630 offset += count;
631 }
632 ret = 0;
633 out:
634 if (fd != STDOUT_FILENO)
635 VOID_TEMP_FAILURE_RETRY(close(fd));
636 return ret;
637}
638
11fdf7f2 639static int do_append(IoCtx& io_ctx,
f67539c2 640 const std::string& oid, const char *infile, int op_size,
11fdf7f2 641 const bool use_striper)
7c673cae 642{
7c673cae
FG
643 bool stdio = (strcmp(infile, "-") == 0);
644 int ret = 0;
645 int fd = STDIN_FILENO;
646 if (!stdio)
f67539c2 647 fd = open(infile, O_RDONLY|O_BINARY);
7c673cae
FG
648 if (fd < 0) {
649 cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl;
650 return 1;
651 }
652 int count = op_size;
653 while (count != 0) {
654 bufferlist indata;
655 count = indata.read_fd(fd, op_size);
656 if (count < 0) {
657 ret = -errno;
658 cerr << "error reading input file " << infile << ": " << cpp_strerror(ret) << std::endl;
659 goto out;
660 }
11fdf7f2 661 ret = detail::append(io_ctx, oid, indata, count, use_striper);
7c673cae
FG
662
663 if (ret < 0) {
664 goto out;
665 }
666 }
667 ret = 0;
668out:
669 if (fd != STDOUT_FILENO)
670 VOID_TEMP_FAILURE_RETRY(close(fd));
671 return ret;
672}
673
674class RadosWatchCtx : public librados::WatchCtx2 {
675 IoCtx& ioctx;
676 string name;
677public:
678 RadosWatchCtx(IoCtx& io, const char *imgname) : ioctx(io), name(imgname) {}
679 ~RadosWatchCtx() override {}
680 void handle_notify(uint64_t notify_id,
681 uint64_t cookie,
682 uint64_t notifier_id,
683 bufferlist& bl) override {
684 cout << "NOTIFY"
685 << " cookie " << cookie
686 << " notify_id " << notify_id
687 << " from " << notifier_id
688 << std::endl;
689 bl.hexdump(cout);
690 ioctx.notify_ack(name, notify_id, cookie, bl);
691 }
692 void handle_error(uint64_t cookie, int err) override {
693 cout << "ERROR"
694 << " cookie " << cookie
695 << " err " << cpp_strerror(err)
696 << std::endl;
697 }
698};
699
700static const char alphanum_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
701
11fdf7f2 702void gen_rand_alphanumeric(char *dest, int size) /* size should be the required string size + 1 */
7c673cae 703{
11fdf7f2 704 const int max = sizeof(alphanum_table) - 2;
7c673cae
FG
705
706 int i;
707 for (i=0; i<size - 1; i++) {
11fdf7f2
TL
708 int pos = generate_random_number(0, max);
709 dest[i] = alphanum_table[pos];
7c673cae
FG
710 }
711 dest[i] = '\0';
7c673cae
FG
712}
713
714struct obj_info {
715 string name;
716 size_t len;
717};
718
719class LoadGen {
720 size_t total_sent;
721 size_t total_completed;
722
723 IoCtx io_ctx;
724 Rados *rados;
725
726 map<int, obj_info> objs;
727
728 utime_t start_time;
729
730 bool going_down;
731
732public:
733 int read_percent;
734 int num_objs;
735 size_t min_obj_len;
11fdf7f2 736 size_t max_obj_len;
7c673cae
FG
737 size_t min_op_len;
738 size_t max_op_len;
739 size_t max_ops;
740 size_t max_backlog;
741 size_t target_throughput;
11fdf7f2 742 size_t offset_align = 0;
7c673cae
FG
743 int run_length;
744
745 enum {
746 OP_READ,
747 OP_WRITE,
748 };
749
750 struct LoadGenOp {
751 int id;
752 int type;
753 string oid;
754 size_t off;
755 size_t len;
756 bufferlist bl;
757 LoadGen *lg;
758 librados::AioCompletion *completion;
759
760 LoadGenOp() : id(0), type(0), off(0), len(0), lg(NULL), completion(NULL) {}
761 explicit LoadGenOp(LoadGen *_lg) : id(0), type(0), off(0), len(0), lg(_lg), completion(NULL) {}
762 };
763
764 int max_op;
765
766 map<int, LoadGenOp *> pending_ops;
767
768 void gen_op(LoadGenOp *op);
769 uint64_t gen_next_op();
770 void run_op(LoadGenOp *op);
771
772 uint64_t cur_sent_rate() {
773 return total_sent / time_passed();
774 }
775
776 uint64_t cur_completed_rate() {
777 return total_completed / time_passed();
778 }
779
780 uint64_t total_expected() {
781 return target_throughput * time_passed();
782 }
783
784 float time_passed() {
785 utime_t now = ceph_clock_now();
786 now -= start_time;
787 uint64_t ns = now.nsec();
788 float total = (float) ns / 1000000000.0;
789 total += now.sec();
790 return total;
791 }
792
9f95a23c
TL
793 ceph::mutex lock = ceph::make_mutex("LoadGen");
794 ceph::condition_variable cond;
7c673cae 795
9f95a23c 796 explicit LoadGen(Rados *_rados) : rados(_rados), going_down(false) {
7c673cae
FG
797 read_percent = 80;
798 min_obj_len = 1024;
799 max_obj_len = 5ull * 1024ull * 1024ull * 1024ull;
800 min_op_len = 1024;
801 target_throughput = 5 * 1024 * 1024; // B/sec
802 max_op_len = 2 * 1024 * 1024;
803 max_ops = 16;
804 max_backlog = target_throughput * 2;
805 run_length = 60;
806
807 total_sent = 0;
808 total_completed = 0;
809 num_objs = 200;
810 max_op = 0;
811 }
812 int bootstrap(const char *pool);
813 int run();
814 void cleanup();
815
816 void io_cb(completion_t c, LoadGenOp *op) {
9f95a23c 817 std::lock_guard l{lock};
7c673cae
FG
818
819 total_completed += op->len;
820
821 double rate = (double)cur_completed_rate() / (1024 * 1024);
822 std::streamsize original_precision = cout.precision();
823 cout.precision(3);
824 cout << "op " << op->id << " completed, throughput=" << rate << "MB/sec" << std::endl;
825 cout.precision(original_precision);
826
827 map<int, LoadGenOp *>::iterator iter = pending_ops.find(op->id);
828 if (iter != pending_ops.end())
829 pending_ops.erase(iter);
830
831 if (!going_down)
832 op->completion->release();
833
834 delete op;
835
9f95a23c 836 cond.notify_all();
7c673cae
FG
837 }
838};
839
840static void _load_gen_cb(completion_t c, void *param)
841{
842 LoadGen::LoadGenOp *op = (LoadGen::LoadGenOp *)param;
843 op->lg->io_cb(c, op);
844}
845
846int LoadGen::bootstrap(const char *pool)
847{
848 char buf[128];
849 int i;
850
851 if (!pool) {
852 cerr << "ERROR: pool name was not specified" << std::endl;
853 return -EINVAL;
854 }
855
856 int ret = rados->ioctx_create(pool, io_ctx);
857 if (ret < 0) {
858 cerr << "error opening pool " << pool << ": " << cpp_strerror(ret) << std::endl;
859 return ret;
860 }
861
862 int buf_len = 1;
863 bufferptr p = buffer::create(buf_len);
864 bufferlist bl;
865 memset(p.c_str(), 0, buf_len);
866 bl.push_back(p);
867
868 list<librados::AioCompletion *> completions;
869 for (i = 0; i < num_objs; i++) {
870 obj_info info;
871 gen_rand_alphanumeric(buf, 16);
872 info.name = "obj-";
873 info.name.append(buf);
11fdf7f2 874 info.len = generate_random_number(min_obj_len, max_obj_len);
7c673cae
FG
875
876 // throttle...
877 while (completions.size() > max_ops) {
878 AioCompletion *c = completions.front();
879 c->wait_for_complete();
880 ret = c->get_return_value();
881 c->release();
882 completions.pop_front();
883 if (ret < 0) {
884 cerr << "aio_write failed" << std::endl;
885 return ret;
886 }
887 }
888
9f95a23c 889 librados::AioCompletion *c = rados->aio_create_completion(nullptr, nullptr);
7c673cae
FG
890 completions.push_back(c);
891 // generate object
892 ret = io_ctx.aio_write(info.name, c, bl, buf_len, info.len - buf_len);
893 if (ret < 0) {
894 cerr << "couldn't write obj: " << info.name << " ret=" << ret << std::endl;
895 return ret;
896 }
897 objs[i] = info;
898 }
899
900 list<librados::AioCompletion *>::iterator iter;
901 for (iter = completions.begin(); iter != completions.end(); ++iter) {
902 AioCompletion *c = *iter;
903 c->wait_for_complete();
904 ret = c->get_return_value();
905 c->release();
906 if (ret < 0) { // yes, we leak.
907 cerr << "aio_write failed" << std::endl;
908 return ret;
909 }
910 }
911 return 0;
912}
913
914void LoadGen::run_op(LoadGenOp *op)
915{
9f95a23c 916 op->completion = rados->aio_create_completion(op, _load_gen_cb);
7c673cae
FG
917
918 switch (op->type) {
919 case OP_READ:
920 io_ctx.aio_read(op->oid, op->completion, &op->bl, op->len, op->off);
921 break;
922 case OP_WRITE:
923 bufferptr p = buffer::create(op->len);
924 memset(p.c_str(), 0, op->len);
925 op->bl.push_back(p);
926
927 io_ctx.aio_write(op->oid, op->completion, op->bl, op->len, op->off);
928 break;
929 }
930
931 total_sent += op->len;
932}
933
934void LoadGen::gen_op(LoadGenOp *op)
935{
11fdf7f2 936 int i = generate_random_number<int>(0, objs.size() - 1);
7c673cae
FG
937 obj_info& info = objs[i];
938 op->oid = info.name;
939
11fdf7f2 940 size_t len = generate_random_number(min_op_len, max_op_len);
7c673cae
FG
941 if (len > info.len)
942 len = info.len;
11fdf7f2 943 size_t off = generate_random_number<size_t>(0, info.len);
7c673cae
FG
944
945 if (off + len > info.len)
946 off = info.len - len;
947
11fdf7f2
TL
948 if (offset_align)
949 off = p2align(off, offset_align);
950
7c673cae
FG
951 op->off = off;
952 op->len = len;
953
11fdf7f2 954 i = generate_random_number(1, 100);
7c673cae
FG
955 if (i > read_percent)
956 op->type = OP_WRITE;
957 else
958 op->type = OP_READ;
959
960 cout << (op->type == OP_READ ? "READ" : "WRITE") << " : oid=" << op->oid << " off=" << op->off << " len=" << op->len << std::endl;
961}
962
963uint64_t LoadGen::gen_next_op()
964{
9f95a23c 965 lock.lock();
7c673cae
FG
966
967 LoadGenOp *op = new LoadGenOp(this);
968 gen_op(op);
969 op->id = max_op++;
970 pending_ops[op->id] = op;
971
9f95a23c 972 lock.unlock();
7c673cae
FG
973
974 run_op(op);
975
976 return op->len;
977}
978
979int LoadGen::run()
980{
981 start_time = ceph_clock_now();
982 utime_t end_time = start_time;
983 end_time += run_length;
984 utime_t stamp_time = start_time;
985 uint32_t total_sec = 0;
986
987 while (1) {
9f95a23c
TL
988 {
989 std::unique_lock l{lock};
990 cond.wait_for(l, 1s);
991 }
7c673cae
FG
992 utime_t now = ceph_clock_now();
993
994 if (now > end_time)
995 break;
996
997 uint64_t expected = total_expected();
9f95a23c 998 lock.lock();
7c673cae
FG
999 uint64_t sent = total_sent;
1000 uint64_t completed = total_completed;
9f95a23c 1001 lock.unlock();
7c673cae
FG
1002
1003 if (now - stamp_time >= utime_t(1, 0)) {
1004 double rate = (double)cur_completed_rate() / (1024 * 1024);
1005 ++total_sec;
1006 std::streamsize original_precision = cout.precision();
1007 cout.precision(3);
20effc67 1008 cout << std::setw(5) << total_sec << ": throughput=" << rate << "MB/sec" << " pending data=" << sent - completed << std::endl;
7c673cae
FG
1009 cout.precision(original_precision);
1010 stamp_time = now;
1011 }
1012
1013 while (sent < expected &&
1014 sent - completed < max_backlog &&
1015 pending_ops.size() < max_ops) {
1016 sent += gen_next_op();
1017 }
1018 }
1019
1020 // get a reference to all pending requests
1021 vector<librados::AioCompletion *> completions;
9f95a23c 1022 lock.lock();
7c673cae
FG
1023 going_down = true;
1024 map<int, LoadGenOp *>::iterator iter;
1025 for (iter = pending_ops.begin(); iter != pending_ops.end(); ++iter) {
1026 LoadGenOp *op = iter->second;
1027 completions.push_back(op->completion);
1028 }
9f95a23c 1029 lock.unlock();
7c673cae
FG
1030
1031 cout << "waiting for all operations to complete" << std::endl;
1032
1033 // now wait on all the pending requests
1034 for (vector<librados::AioCompletion *>::iterator citer = completions.begin(); citer != completions.end(); ++citer) {
1035 librados::AioCompletion *c = *citer;
1036 c->wait_for_complete();
1037 c->release();
1038 }
1039
1040 return 0;
1041}
1042
1043void LoadGen::cleanup()
1044{
1045 cout << "cleaning up objects" << std::endl;
1046 map<int, obj_info>::iterator iter;
1047 for (iter = objs.begin(); iter != objs.end(); ++iter) {
1048 obj_info& info = iter->second;
1049 int ret = io_ctx.remove(info.name);
1050 if (ret < 0)
1051 cerr << "couldn't remove obj: " << info.name << " ret=" << ret << std::endl;
1052 }
1053}
1054
1055enum OpWriteDest {
1056 OP_WRITE_DEST_OBJ = 2 << 0,
1057 OP_WRITE_DEST_OMAP = 2 << 1,
1058 OP_WRITE_DEST_XATTR = 2 << 2,
1059};
1060
1061class RadosBencher : public ObjBencher {
1062 librados::AioCompletion **completions;
1063 librados::Rados& rados;
1064 librados::IoCtx& io_ctx;
1065 librados::NObjectIterator oi;
1066 bool iterator_valid;
1067 OpWriteDest write_destination;
1068
1069protected:
1070 int completions_init(int concurrentios) override {
1071 completions = new librados::AioCompletion *[concurrentios];
1072 return 0;
1073 }
1074 void completions_done() override {
1075 delete[] completions;
1076 completions = NULL;
1077 }
1078 int create_completion(int slot, void (*cb)(void *, void*), void *arg) override {
9f95a23c 1079 completions[slot] = rados.aio_create_completion((void *) arg, cb);
7c673cae
FG
1080
1081 if (!completions[slot])
1082 return -EINVAL;
1083
1084 return 0;
1085 }
1086 void release_completion(int slot) override {
1087 completions[slot]->release();
1088 completions[slot] = 0;
1089 }
1090
1091 int aio_read(const std::string& oid, int slot, bufferlist *pbl, size_t len,
1092 size_t offset) override {
11fdf7f2 1093 return io_ctx.aio_read(oid, completions[slot], pbl, len, offset);
7c673cae
FG
1094 }
1095
1096 int aio_write(const std::string& oid, int slot, bufferlist& bl, size_t len,
1097 size_t offset) override {
1098 librados::ObjectWriteOperation op;
1099
1100 if (write_destination & OP_WRITE_DEST_OBJ) {
1101 if (data.hints)
1102 op.set_alloc_hint2(data.object_size, data.op_size,
1103 ALLOC_HINT_FLAG_SEQUENTIAL_WRITE |
1104 ALLOC_HINT_FLAG_SEQUENTIAL_READ |
1105 ALLOC_HINT_FLAG_APPEND_ONLY |
1106 ALLOC_HINT_FLAG_IMMUTABLE);
1107 op.write(offset, bl);
1108 }
1109
1110 if (write_destination & OP_WRITE_DEST_OMAP) {
1111 std::map<std::string, librados::bufferlist> omap;
1112 omap[string("bench-omap-key-") + stringify(offset)] = bl;
1113 op.omap_set(omap);
1114 }
1115
1116 if (write_destination & OP_WRITE_DEST_XATTR) {
1117 char key[80];
1118 snprintf(key, sizeof(key), "bench-xattr-key-%d", (int)offset);
1119 op.setxattr(key, bl);
1120 }
1121
1122 return io_ctx.aio_operate(oid, completions[slot], &op);
1123 }
1124
1125 int aio_remove(const std::string& oid, int slot) override {
1126 return io_ctx.aio_remove(oid, completions[slot]);
1127 }
1128
1129 int sync_read(const std::string& oid, bufferlist& bl, size_t len) override {
1130 return io_ctx.read(oid, bl, len, 0);
1131 }
1132 int sync_write(const std::string& oid, bufferlist& bl, size_t len) override {
1133 return io_ctx.write_full(oid, bl);
1134 }
1135
1136 int sync_remove(const std::string& oid) override {
1137 return io_ctx.remove(oid);
1138 }
1139
1140 bool completion_is_done(int slot) override {
9f95a23c 1141 return completions[slot] && completions[slot]->is_complete();
7c673cae
FG
1142 }
1143
1144 int completion_wait(int slot) override {
9f95a23c 1145 return completions[slot]->wait_for_complete_and_cb();
7c673cae
FG
1146 }
1147 int completion_ret(int slot) override {
1148 return completions[slot]->get_return_value();
1149 }
1150
1151 bool get_objects(std::list<Object>* objects, int num) override {
1152 int count = 0;
1153
1154 if (!iterator_valid) {
1155 oi = io_ctx.nobjects_begin();
1156 iterator_valid = true;
1157 }
1158
1159 librados::NObjectIterator ei = io_ctx.nobjects_end();
1160
1161 if (oi == ei) {
1162 iterator_valid = false;
1163 return false;
1164 }
1165
1166 objects->clear();
1167 for ( ; oi != ei && count < num; ++oi) {
1168 Object obj(oi->get_oid(), oi->get_nspace());
1169 objects->push_back(obj);
1170 ++count;
1171 }
1172
1173 return true;
1174 }
1175
1176 void set_namespace( const std::string& ns) override {
1177 io_ctx.set_namespace(ns);
1178 }
1179
1180public:
1181 RadosBencher(CephContext *cct_, librados::Rados& _r, librados::IoCtx& _i)
1182 : ObjBencher(cct_), completions(NULL), rados(_r), io_ctx(_i), iterator_valid(false), write_destination(OP_WRITE_DEST_OBJ) {}
1183 ~RadosBencher() override { }
1184
1185 void set_write_destination(OpWriteDest dest) {
1186 write_destination = dest;
1187 }
1188};
1189
1190static int do_lock_cmd(std::vector<const char*> &nargs,
1191 const std::map < std::string, std::string > &opts,
1192 IoCtx *ioctx,
1193 Formatter *formatter)
1194{
1195 if (nargs.size() < 3)
1196 usage_exit();
1197
1198 string cmd(nargs[1]);
1199 string oid(nargs[2]);
1200
1201 string lock_tag;
1202 string lock_cookie;
1203 string lock_description;
1204 int lock_duration = 0;
f67539c2 1205 ClsLockType lock_type = ClsLockType::EXCLUSIVE;
7c673cae
FG
1206
1207 map<string, string>::const_iterator i;
1208 i = opts.find("lock-tag");
1209 if (i != opts.end()) {
1210 lock_tag = i->second;
1211 }
1212 i = opts.find("lock-cookie");
1213 if (i != opts.end()) {
1214 lock_cookie = i->second;
1215 }
1216 i = opts.find("lock-description");
1217 if (i != opts.end()) {
1218 lock_description = i->second;
1219 }
1220 i = opts.find("lock-duration");
1221 if (i != opts.end()) {
1222 if (rados_sistrtoll(i, &lock_duration)) {
1223 return -EINVAL;
1224 }
1225 }
1226 i = opts.find("lock-type");
1227 if (i != opts.end()) {
1228 const string& type_str = i->second;
1229 if (type_str.compare("exclusive") == 0) {
f67539c2 1230 lock_type = ClsLockType::EXCLUSIVE;
7c673cae 1231 } else if (type_str.compare("shared") == 0) {
f67539c2 1232 lock_type = ClsLockType::SHARED;
7c673cae
FG
1233 } else {
1234 cerr << "unknown lock type was specified, aborting" << std::endl;
1235 return -EINVAL;
1236 }
1237 }
1238
1239 if (cmd.compare("list") == 0) {
1240 list<string> locks;
1241 int ret = rados::cls::lock::list_locks(ioctx, oid, &locks);
1242 if (ret < 0) {
1243 cerr << "ERROR: rados_list_locks(): " << cpp_strerror(ret) << std::endl;
1244 return ret;
1245 }
1246
1247 formatter->open_object_section("object");
1248 formatter->dump_string("objname", oid);
1249 formatter->open_array_section("locks");
1250 list<string>::iterator iter;
1251 for (iter = locks.begin(); iter != locks.end(); ++iter) {
1252 formatter->open_object_section("lock");
1253 formatter->dump_string("name", *iter);
1254 formatter->close_section();
1255 }
1256 formatter->close_section();
1257 formatter->close_section();
1258 formatter->flush(cout);
1259 return 0;
1260 }
1261
1262 if (nargs.size() < 4)
1263 usage_exit();
1264
1265 string lock_name(nargs[3]);
1266
1267 if (cmd.compare("info") == 0) {
1268 map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t> lockers;
f67539c2 1269 ClsLockType type = ClsLockType::NONE;
7c673cae
FG
1270 string tag;
1271 int ret = rados::cls::lock::get_lock_info(ioctx, oid, lock_name, &lockers, &type, &tag);
1272 if (ret < 0) {
1273 cerr << "ERROR: rados_lock_get_lock_info(): " << cpp_strerror(ret) << std::endl;
1274 return ret;
1275 }
1276
1277 formatter->open_object_section("lock");
1278 formatter->dump_string("name", lock_name);
1279 formatter->dump_string("type", cls_lock_type_str(type));
1280 formatter->dump_string("tag", tag);
1281 formatter->open_array_section("lockers");
1282 map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t>::iterator iter;
1283 for (iter = lockers.begin(); iter != lockers.end(); ++iter) {
1284 const rados::cls::lock::locker_id_t& id = iter->first;
1285 const rados::cls::lock::locker_info_t& info = iter->second;
1286 formatter->open_object_section("locker");
1287 formatter->dump_stream("name") << id.locker;
1288 formatter->dump_string("cookie", id.cookie);
1289 formatter->dump_string("description", info.description);
1290 formatter->dump_stream("expiration") << info.expiration;
11fdf7f2 1291 formatter->dump_stream("addr") << info.addr.get_legacy_str();
7c673cae
FG
1292 formatter->close_section();
1293 }
1294 formatter->close_section();
1295 formatter->close_section();
1296 formatter->flush(cout);
1297
1298 return ret;
1299 } else if (cmd.compare("get") == 0) {
1300 rados::cls::lock::Lock l(lock_name);
1301 l.set_cookie(lock_cookie);
1302 l.set_tag(lock_tag);
1303 l.set_duration(utime_t(lock_duration, 0));
1304 l.set_description(lock_description);
1305 int ret;
1306 switch (lock_type) {
f67539c2 1307 case ClsLockType::SHARED:
7c673cae
FG
1308 ret = l.lock_shared(ioctx, oid);
1309 break;
1310 default:
1311 ret = l.lock_exclusive(ioctx, oid);
1312 }
1313 if (ret < 0) {
1314 cerr << "ERROR: failed locking: " << cpp_strerror(ret) << std::endl;
1315 return ret;
1316 }
1317
1318 return ret;
1319 }
1320
1321 if (nargs.size() < 5)
1322 usage_exit();
1323
1324 if (cmd.compare("break") == 0) {
20effc67 1325 const char* locker = nargs[4];
7c673cae
FG
1326 rados::cls::lock::Lock l(lock_name);
1327 l.set_cookie(lock_cookie);
1328 l.set_tag(lock_tag);
1329 entity_name_t name;
1330 if (!name.parse(locker)) {
1331 cerr << "ERROR: failed to parse locker name (" << locker << ")" << std::endl;
1332 return -EINVAL;
1333 }
1334 int ret = l.break_lock(ioctx, oid, name);
1335 if (ret < 0) {
1336 cerr << "ERROR: failed breaking lock: " << cpp_strerror(ret) << std::endl;
1337 return ret;
1338 }
1339 } else {
1340 usage_exit();
1341 }
1342
1343 return 0;
1344}
1345
1346static int do_cache_flush(IoCtx& io_ctx, string oid)
1347{
1348 ObjectReadOperation op;
1349 op.cache_flush();
1350 librados::AioCompletion *completion =
1351 librados::Rados::aio_create_completion();
1352 io_ctx.aio_operate(oid.c_str(), completion, &op,
1353 librados::OPERATION_IGNORE_CACHE |
1354 librados::OPERATION_IGNORE_OVERLAY,
1355 NULL);
9f95a23c 1356 completion->wait_for_complete();
7c673cae
FG
1357 int r = completion->get_return_value();
1358 completion->release();
1359 return r;
1360}
1361
1362static int do_cache_try_flush(IoCtx& io_ctx, string oid)
1363{
1364 ObjectReadOperation op;
1365 op.cache_try_flush();
1366 librados::AioCompletion *completion =
1367 librados::Rados::aio_create_completion();
1368 io_ctx.aio_operate(oid.c_str(), completion, &op,
1369 librados::OPERATION_IGNORE_CACHE |
1370 librados::OPERATION_IGNORE_OVERLAY |
1371 librados::OPERATION_SKIPRWLOCKS,
1372 NULL);
9f95a23c 1373 completion->wait_for_complete();
7c673cae
FG
1374 int r = completion->get_return_value();
1375 completion->release();
1376 return r;
1377}
1378
1379static int do_cache_evict(IoCtx& io_ctx, string oid)
1380{
1381 ObjectReadOperation op;
1382 op.cache_evict();
1383 librados::AioCompletion *completion =
1384 librados::Rados::aio_create_completion();
1385 io_ctx.aio_operate(oid.c_str(), completion, &op,
1386 librados::OPERATION_IGNORE_CACHE |
1387 librados::OPERATION_IGNORE_OVERLAY |
1388 librados::OPERATION_SKIPRWLOCKS,
1389 NULL);
9f95a23c 1390 completion->wait_for_complete();
7c673cae
FG
1391 int r = completion->get_return_value();
1392 completion->release();
1393 return r;
1394}
1395
1396static int do_cache_flush_evict_all(IoCtx& io_ctx, bool blocking)
1397{
1398 int errors = 0;
1399 io_ctx.set_namespace(all_nspaces);
1400 try {
1401 librados::NObjectIterator i = io_ctx.nobjects_begin();
1402 librados::NObjectIterator i_end = io_ctx.nobjects_end();
1403 for (; i != i_end; ++i) {
1404 int r;
1405 cout << i->get_nspace() << "\t" << i->get_oid() << "\t" << i->get_locator() << std::endl;
1406 if (i->get_locator().size()) {
1407 io_ctx.locator_set_key(i->get_locator());
1408 } else {
1409 io_ctx.locator_set_key(string());
1410 }
1411 io_ctx.set_namespace(i->get_nspace());
1412 snap_set_t ls;
1413 io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
1414 r = io_ctx.list_snaps(i->get_oid(), &ls);
1415 if (r < 0) {
1416 cerr << "error listing snap shots " << i->get_nspace() << "/" << i->get_oid() << ": "
1417 << cpp_strerror(r) << std::endl;
1418 ++errors;
1419 continue;
1420 }
1421 std::vector<clone_info_t>::iterator ci = ls.clones.begin();
1422 // no snapshots
1423 if (ci == ls.clones.end()) {
1424 io_ctx.snap_set_read(CEPH_NOSNAP);
1425 if (blocking)
1426 r = do_cache_flush(io_ctx, i->get_oid());
1427 else
1428 r = do_cache_try_flush(io_ctx, i->get_oid());
1429 if (r < 0) {
1430 cerr << "failed to flush " << i->get_nspace() << "/" << i->get_oid() << ": "
1431 << cpp_strerror(r) << std::endl;
1432 ++errors;
1433 continue;
1434 }
1435 r = do_cache_evict(io_ctx, i->get_oid());
1436 if (r < 0) {
1437 cerr << "failed to evict " << i->get_nspace() << "/" << i->get_oid() << ": "
1438 << cpp_strerror(r) << std::endl;
1439 ++errors;
1440 continue;
1441 }
1442 } else {
1443 // has snapshots
1444 for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
1445 ci != ls.clones.end(); ++ci) {
1446 io_ctx.snap_set_read(ci->cloneid);
1447 if (blocking)
1448 r = do_cache_flush(io_ctx, i->get_oid());
1449 else
1450 r = do_cache_try_flush(io_ctx, i->get_oid());
1451 if (r < 0) {
1452 cerr << "failed to flush " << i->get_nspace() << "/" << i->get_oid() << ": "
1453 << cpp_strerror(r) << std::endl;
1454 ++errors;
1455 break;
1456 }
1457 r = do_cache_evict(io_ctx, i->get_oid());
1458 if (r < 0) {
1459 cerr << "failed to evict " << i->get_nspace() << "/" << i->get_oid() << ": "
1460 << cpp_strerror(r) << std::endl;
1461 ++errors;
1462 break;
1463 }
1464 }
1465 }
1466 }
1467 }
f64942e4 1468 catch (const std::exception& e) {
7c673cae
FG
1469 cerr << e.what() << std::endl;
1470 return -1;
1471 }
1472 return errors ? -1 : 0;
1473}
1474
1475static int do_get_inconsistent_pg_cmd(const std::vector<const char*> &nargs,
1476 Rados& rados,
1477 Formatter& formatter)
1478{
1479 if (nargs.size() < 2) {
1480 usage_exit();
1481 }
1482 int64_t pool_id = rados.pool_lookup(nargs[1]);
1483 if (pool_id < 0) {
1484 cerr << "pool \"" << nargs[1] << "\" not found" << std::endl;
1485 return (int)pool_id;
1486 }
1487 std::vector<PlacementGroup> pgs;
1488 int ret = rados.get_inconsistent_pgs(pool_id, &pgs);
1489 if (ret) {
1490 return ret;
1491 }
1492 formatter.open_array_section("pgs");
1493 for (auto& pg : pgs) {
1494 formatter.dump_stream("pg") << pg;
1495 }
1496 formatter.close_section();
1497 formatter.flush(cout);
1498 cout << std::endl;
1499 return 0;
1500}
1501
1502static void dump_errors(const err_t &err, Formatter &f, const char *name)
1503{
1504 f.open_array_section(name);
1505 if (err.has_shard_missing())
1506 f.dump_string("error", "missing");
1507 if (err.has_stat_error())
1508 f.dump_string("error", "stat_error");
1509 if (err.has_read_error())
1510 f.dump_string("error", "read_error");
94b18763
FG
1511 if (err.has_data_digest_mismatch_info())
1512 f.dump_string("error", "data_digest_mismatch_info");
1513 if (err.has_omap_digest_mismatch_info())
1514 f.dump_string("error", "omap_digest_mismatch_info");
1515 if (err.has_size_mismatch_info())
1516 f.dump_string("error", "size_mismatch_info");
7c673cae
FG
1517 if (err.has_ec_hash_error())
1518 f.dump_string("error", "ec_hash_error");
1519 if (err.has_ec_size_error())
1520 f.dump_string("error", "ec_size_error");
94b18763
FG
1521 if (err.has_info_missing())
1522 f.dump_string("error", "info_missing");
1523 if (err.has_info_corrupted())
1524 f.dump_string("error", "info_corrupted");
1525 if (err.has_obj_size_info_mismatch())
1526 f.dump_string("error", "obj_size_info_mismatch");
1527 if (err.has_snapset_missing())
1528 f.dump_string("error", "snapset_missing");
1529 if (err.has_snapset_corrupted())
1530 f.dump_string("error", "snapset_corrupted");
1531 if (err.has_hinfo_missing())
1532 f.dump_string("error", "hinfo_missing");
1533 if (err.has_hinfo_corrupted())
1534 f.dump_string("error", "hinfo_corrupted");
7c673cae
FG
1535 f.close_section();
1536}
1537
1538static void dump_shard(const shard_info_t& shard,
1539 const inconsistent_obj_t& inc,
1540 Formatter &f)
1541{
1542 dump_errors(shard, f, "errors");
1543
1544 if (shard.has_shard_missing())
1545 return;
1546
1547 if (!shard.has_stat_error())
1548 f.dump_unsigned("size", shard.size);
1549 if (shard.omap_digest_present) {
1550 f.dump_format("omap_digest", "0x%08x", shard.omap_digest);
1551 }
1552 if (shard.data_digest_present) {
1553 f.dump_format("data_digest", "0x%08x", shard.data_digest);
1554 }
1555
94b18763
FG
1556 if ((inc.union_shards.has_info_missing()
1557 || inc.union_shards.has_info_corrupted()
1558 || inc.has_object_info_inconsistency()
1559 || shard.has_obj_size_info_mismatch()) &&
1560 !shard.has_info_missing()) {
7c673cae 1561 map<std::string, ceph::bufferlist>::iterator k = (const_cast<shard_info_t&>(shard)).attrs.find(OI_ATTR);
11fdf7f2 1562 ceph_assert(k != shard.attrs.end()); // Can't be missing
94b18763
FG
1563 if (!shard.has_info_corrupted()) {
1564 object_info_t oi;
1565 bufferlist bl;
11fdf7f2
TL
1566 auto bliter = k->second.cbegin();
1567 decode(oi, bliter); // Can't be corrupted
94b18763
FG
1568 f.open_object_section("object_info");
1569 oi.dump(&f);
1570 f.close_section();
1571 } else {
1572 bool b64;
1573 f.dump_string("object_info", cleanbin(k->second, b64));
1574 }
7c673cae 1575 }
94b18763
FG
1576 if ((inc.union_shards.has_snapset_missing()
1577 || inc.union_shards.has_snapset_corrupted()
1578 || inc.has_snapset_inconsistency()) &&
1579 !shard.has_snapset_missing()) {
3a9019d9 1580 map<std::string, ceph::bufferlist>::iterator k = (const_cast<shard_info_t&>(shard)).attrs.find(SS_ATTR);
11fdf7f2 1581 ceph_assert(k != shard.attrs.end()); // Can't be missing
94b18763
FG
1582 if (!shard.has_snapset_corrupted()) {
1583 SnapSet ss;
1584 bufferlist bl;
11fdf7f2 1585 auto bliter = k->second.cbegin();
94b18763
FG
1586 decode(ss, bliter); // Can't be corrupted
1587 f.open_object_section("snapset");
1588 ss.dump(&f);
1589 f.close_section();
1590 } else {
1591 bool b64;
1592 f.dump_string("snapset", cleanbin(k->second, b64));
1593 }
1594 }
1595 if ((inc.union_shards.has_hinfo_missing()
1596 || inc.union_shards.has_hinfo_corrupted()
1597 || inc.has_hinfo_inconsistency()) &&
1598 !shard.has_hinfo_missing()) {
1599 map<std::string, ceph::bufferlist>::iterator k = (const_cast<shard_info_t&>(shard)).attrs.find(ECUtil::get_hinfo_key());
11fdf7f2 1600 ceph_assert(k != shard.attrs.end()); // Can't be missing
94b18763
FG
1601 if (!shard.has_hinfo_corrupted()) {
1602 ECUtil::HashInfo hi;
1603 bufferlist bl;
11fdf7f2 1604 auto bliter = k->second.cbegin();
94b18763
FG
1605 decode(hi, bliter); // Can't be corrupted
1606 f.open_object_section("hashinfo");
1607 hi.dump(&f);
1608 f.close_section();
1609 } else {
1610 bool b64;
1611 f.dump_string("hashinfo", cleanbin(k->second, b64));
1612 }
3a9019d9 1613 }
94b18763 1614 if (inc.has_attr_name_mismatch() || inc.has_attr_value_mismatch()) {
7c673cae
FG
1615 f.open_array_section("attrs");
1616 for (auto kv : shard.attrs) {
94b18763
FG
1617 // System attribute handled above
1618 if (kv.first == OI_ATTR || kv.first[0] != '_')
1619 continue;
7c673cae 1620 f.open_object_section("attr");
94b18763
FG
1621 // Skip leading underscore since only giving user attrs
1622 f.dump_string("name", kv.first.substr(1));
7c673cae
FG
1623 bool b64;
1624 f.dump_string("value", cleanbin(kv.second, b64));
1625 f.dump_bool("Base64", b64);
1626 f.close_section();
1627 }
1628 f.close_section();
1629 }
1630}
1631
1632static void dump_obj_errors(const obj_err_t &err, Formatter &f)
1633{
1634 f.open_array_section("errors");
1635 if (err.has_object_info_inconsistency())
1636 f.dump_string("error", "object_info_inconsistency");
1637 if (err.has_data_digest_mismatch())
1638 f.dump_string("error", "data_digest_mismatch");
1639 if (err.has_omap_digest_mismatch())
1640 f.dump_string("error", "omap_digest_mismatch");
1641 if (err.has_size_mismatch())
1642 f.dump_string("error", "size_mismatch");
1643 if (err.has_attr_value_mismatch())
1644 f.dump_string("error", "attr_value_mismatch");
1645 if (err.has_attr_name_mismatch())
1646 f.dump_string("error", "attr_name_mismatch");
3a9019d9
FG
1647 if (err.has_snapset_inconsistency())
1648 f.dump_string("error", "snapset_inconsistency");
94b18763
FG
1649 if (err.has_hinfo_inconsistency())
1650 f.dump_string("error", "hinfo_inconsistency");
eafe8130
TL
1651 if (err.has_size_too_large())
1652 f.dump_string("error", "size_too_large");
7c673cae
FG
1653 f.close_section();
1654}
1655
1656static void dump_object_id(const object_id_t& object,
1657 Formatter &f)
1658{
1659 f.dump_string("name", object.name);
1660 f.dump_string("nspace", object.nspace);
1661 f.dump_string("locator", object.locator);
1662 switch (object.snap) {
1663 case CEPH_NOSNAP:
1664 f.dump_string("snap", "head");
1665 break;
1666 case CEPH_SNAPDIR:
1667 f.dump_string("snap", "snapdir");
1668 break;
1669 default:
1670 f.dump_unsigned("snap", object.snap);
1671 break;
1672 }
1673}
1674
1675static void dump_inconsistent(const inconsistent_obj_t& inc,
1676 Formatter &f)
1677{
1678 f.open_object_section("object");
1679 dump_object_id(inc.object, f);
1680 f.dump_unsigned("version", inc.version);
1681 f.close_section();
1682
1683 dump_obj_errors(inc, f);
1684 dump_errors(inc.union_shards, f, "union_shard_errors");
1685 for (const auto& shard_info : inc.shards) {
1686 shard_info_t shard = const_cast<shard_info_t&>(shard_info.second);
1687 if (shard.selected_oi) {
1688 object_info_t oi;
1689 bufferlist bl;
1690 auto k = shard.attrs.find(OI_ATTR);
11fdf7f2
TL
1691 ceph_assert(k != shard.attrs.end()); // Can't be missing
1692 auto bliter = k->second.cbegin();
1693 decode(oi, bliter); // Can't be corrupted
94b18763
FG
1694 f.open_object_section("selected_object_info");
1695 oi.dump(&f);
1696 f.close_section();
7c673cae
FG
1697 break;
1698 }
1699 }
1700 f.open_array_section("shards");
1701 for (const auto& shard_info : inc.shards) {
1702 f.open_object_section("shard");
1703 auto& osd_shard = shard_info.first;
1704 f.dump_int("osd", osd_shard.osd);
b5b8bbf5 1705 f.dump_bool("primary", shard_info.second.primary);
7c673cae
FG
1706 auto shard = osd_shard.shard;
1707 if (shard != shard_id_t::NO_SHARD)
1708 f.dump_unsigned("shard", shard);
1709 dump_shard(shard_info.second, inc, f);
1710 f.close_section();
1711 }
1712 f.close_section();
1713}
1714
1715static void dump_inconsistent(const inconsistent_snapset_t& inc,
1716 Formatter &f)
1717{
1718 dump_object_id(inc.object, f);
1719
94b18763
FG
1720 if (inc.ss_bl.length()) {
1721 SnapSet ss;
1722 bufferlist bl = inc.ss_bl;
11fdf7f2 1723 auto bliter = bl.cbegin();
94b18763
FG
1724 decode(ss, bliter); // Can't be corrupted
1725 f.open_object_section("snapset");
1726 ss.dump(&f);
1727 f.close_section();
1728 }
7c673cae 1729 f.open_array_section("errors");
94b18763
FG
1730 if (inc.snapset_missing())
1731 f.dump_string("error", "snapset_missing");
1732 if (inc.snapset_corrupted())
1733 f.dump_string("error", "snapset_corrupted");
1734 if (inc.info_missing())
1735 f.dump_string("error", "info_missing");
1736 if (inc.info_corrupted())
1737 f.dump_string("error", "info_corrupted");
1738 if (inc.snapset_error())
1739 f.dump_string("error", "snapset_error");
7c673cae
FG
1740 if (inc.headless())
1741 f.dump_string("error", "headless");
1742 if (inc.size_mismatch())
1743 f.dump_string("error", "size_mismatch");
1744 if (inc.extra_clones())
1745 f.dump_string("error", "extra_clones");
1746 if (inc.clone_missing())
1747 f.dump_string("error", "clone_missing");
1748 f.close_section();
1749
1750 if (inc.extra_clones()) {
1751 f.open_array_section("extra clones");
1752 for (auto snap : inc.clones) {
1753 f.dump_unsigned("snap", snap);
1754 }
1755 f.close_section();
1756 }
1757
1758 if (inc.clone_missing()) {
1759 f.open_array_section("missing");
1760 for (auto snap : inc.missing) {
1761 f.dump_unsigned("snap", snap);
1762 }
1763 f.close_section();
1764 }
1765}
1766
1767// dispatch the call by type
1768static int do_get_inconsistent(Rados& rados,
1769 const PlacementGroup& pg,
1770 const librados::object_id_t &start,
1771 unsigned max_return,
1772 AioCompletion *c,
1773 std::vector<inconsistent_obj_t>* objs,
1774 uint32_t* interval)
1775{
1776 return rados.get_inconsistent_objects(pg, start, max_return, c,
1777 objs, interval);
1778}
1779
1780static int do_get_inconsistent(Rados& rados,
1781 const PlacementGroup& pg,
1782 const librados::object_id_t &start,
1783 unsigned max_return,
1784 AioCompletion *c,
1785 std::vector<inconsistent_snapset_t>* snapsets,
1786 uint32_t* interval)
1787{
1788 return rados.get_inconsistent_snapsets(pg, start, max_return, c,
1789 snapsets, interval);
1790}
1791
1792template <typename T>
1793static int do_get_inconsistent_cmd(const std::vector<const char*> &nargs,
1794 Rados& rados,
1795 Formatter& formatter)
1796{
1797 if (nargs.size() < 2) {
1798 usage_exit();
1799 }
1800 PlacementGroup pg;
1801 int ret = 0;
1802 ret = pg.parse(nargs[1]);
1803 if (!ret) {
1804 cerr << "bad pg: " << nargs[1] << std::endl;
1805 return ret;
1806 }
1807 uint32_t interval = 0, first_interval = 0;
1808 const unsigned max_item_num = 32;
1809 bool opened = false;
1810 for (librados::object_id_t start;;) {
1811 std::vector<T> items;
1812 auto completion = librados::Rados::aio_create_completion();
1813 ret = do_get_inconsistent(rados, pg, start, max_item_num, completion,
1814 &items, &interval);
9f95a23c 1815 completion->wait_for_complete();
7c673cae
FG
1816 ret = completion->get_return_value();
1817 completion->release();
1818 if (ret < 0) {
1819 if (ret == -EAGAIN)
1820 cerr << "interval#" << interval << " expired." << std::endl;
1821 else if (ret == -ENOENT)
1822 cerr << "No scrub information available for pg " << pg << std::endl;
7c673cae
FG
1823 break;
1824 }
1825 // It must be the same interval every time. EAGAIN would
1826 // occur if interval changes.
11fdf7f2 1827 ceph_assert(start.name.empty() || first_interval == interval);
7c673cae
FG
1828 if (start.name.empty()) {
1829 first_interval = interval;
1830 formatter.open_object_section("info");
1831 formatter.dump_int("epoch", interval);
1832 formatter.open_array_section("inconsistents");
1833 opened = true;
1834 }
1835 for (auto& inc : items) {
1836 formatter.open_object_section("inconsistent");
1837 dump_inconsistent(inc, formatter);
1838 formatter.close_section();
1839 }
1840 if (items.size() < max_item_num) {
1841 formatter.close_section();
1842 break;
1843 }
1844 if (!items.empty()) {
1845 start = items.back().object;
1846 }
1847 items.clear();
1848 }
1849 if (opened) {
1850 formatter.close_section();
1851 formatter.flush(cout);
1852 }
1853 return ret;
1854}
1855
f67539c2
TL
1856static std::string prettify(const std::string& s)
1857{
1858 if (std::find_if_not(s.begin(), s.end(),
1859 (int (*)(int))isprint) != s.end()) {
1860 return "(binary key)";
1861 } else {
1862 return s;
1863 }
1864}
1865
7c673cae
FG
1866/**********************************************
1867
1868**********************************************/
1869static int rados_tool_common(const std::map < std::string, std::string > &opts,
1870 std::vector<const char*> &nargs)
1871{
1872 int ret;
1873 bool create_pool = false;
1874 const char *pool_name = NULL;
1875 const char *target_pool_name = NULL;
1876 string oloc, target_oloc, nspace, target_nspace;
1877 int concurrent_ios = 16;
1878 unsigned op_size = default_op_size;
1879 unsigned object_size = 0;
1880 unsigned max_objects = 0;
1881 uint64_t obj_offset = 0;
9f95a23c 1882 bool obj_offset_specified = false;
7c673cae
FG
1883 bool block_size_specified = false;
1884 int bench_write_dest = 0;
1885 bool cleanup = true;
1886 bool hints = true; // for rados bench
11fdf7f2 1887 bool reuse_bench = false;
7c673cae
FG
1888 bool no_verify = false;
1889 bool use_striper = false;
1890 bool with_clones = false;
1891 const char *snapname = NULL;
1892 snap_t snapid = CEPH_NOSNAP;
1893 std::map<std::string, std::string>::const_iterator i;
1894
11fdf7f2 1895 uint64_t offset_align = 0;
7c673cae
FG
1896 uint64_t min_obj_len = 0;
1897 uint64_t max_obj_len = 0;
1898 uint64_t min_op_len = 0;
1899 uint64_t max_op_len = 0;
1900 uint64_t max_ops = 0;
1901 uint64_t max_backlog = 0;
1902 uint64_t target_throughput = 0;
1903 int64_t read_percent = -1;
1904 uint64_t num_objs = 0;
1905 int run_length = 0;
1906
1907 bool show_time = false;
1908 bool wildcard = false;
1909
1910 std::string run_name;
1911 std::string prefix;
1912 bool forcefull = false;
11fdf7f2 1913 unique_ptr<Formatter> formatter = nullptr;
7c673cae
FG
1914 bool pretty_format = false;
1915 const char *output = NULL;
f67539c2
TL
1916 std::optional<std::string> omap_key;
1917 std::optional<std::string> obj_name;
1918 std::string input_file;
11fdf7f2 1919 bool with_reference = false;
7c673cae
FG
1920
1921 Rados rados;
1922 IoCtx io_ctx;
7c673cae
FG
1923
1924 i = opts.find("create");
1925 if (i != opts.end()) {
1926 create_pool = true;
1927 }
1928 i = opts.find("pool");
1929 if (i != opts.end()) {
1930 pool_name = i->second.c_str();
1931 }
1932 i = opts.find("target_pool");
1933 if (i != opts.end()) {
1934 target_pool_name = i->second.c_str();
1935 }
1936 i = opts.find("object_locator");
1937 if (i != opts.end()) {
1938 oloc = i->second;
1939 }
1940 i = opts.find("target_locator");
1941 if (i != opts.end()) {
1942 target_oloc = i->second;
1943 }
1944 i = opts.find("target_nspace");
1945 if (i != opts.end()) {
1946 target_nspace = i->second;
1947 }
1948 i = opts.find("concurrent-ios");
1949 if (i != opts.end()) {
1950 if (rados_sistrtoll(i, &concurrent_ios)) {
1951 return -EINVAL;
1952 }
1953 }
1954 i = opts.find("run-name");
1955 if (i != opts.end()) {
1956 run_name = i->second;
1957 }
1958
1959 i = opts.find("force-full");
1960 if (i != opts.end()) {
1961 forcefull = true;
1962 }
1963 i = opts.find("prefix");
1964 if (i != opts.end()) {
1965 prefix = i->second;
1966 }
1967 i = opts.find("block-size");
1968 if (i != opts.end()) {
1969 if (rados_sistrtoll(i, &op_size)) {
1970 return -EINVAL;
1971 }
1972 block_size_specified = true;
1973 }
1974 i = opts.find("object-size");
1975 if (i != opts.end()) {
1976 if (rados_sistrtoll(i, &object_size)) {
1977 return -EINVAL;
1978 }
1979 block_size_specified = true;
1980 }
1981 i = opts.find("max-objects");
1982 if (i != opts.end()) {
1983 if (rados_sistrtoll(i, &max_objects)) {
1984 return -EINVAL;
1985 }
1986 }
1987 i = opts.find("offset");
1988 if (i != opts.end()) {
1989 if (rados_sistrtoll(i, &obj_offset)) {
1990 return -EINVAL;
1991 }
9f95a23c 1992 obj_offset_specified = true;
7c673cae
FG
1993 }
1994 i = opts.find("snap");
1995 if (i != opts.end()) {
1996 snapname = i->second.c_str();
1997 }
1998 i = opts.find("snapid");
1999 if (i != opts.end()) {
2000 if (rados_sistrtoll(i, &snapid)) {
2001 return -EINVAL;
2002 }
2003 }
2004 i = opts.find("min-object-size");
2005 if (i != opts.end()) {
2006 if (rados_sistrtoll(i, &min_obj_len)) {
2007 return -EINVAL;
2008 }
2009 }
2010 i = opts.find("max-object-size");
2011 if (i != opts.end()) {
2012 if (rados_sistrtoll(i, &max_obj_len)) {
2013 return -EINVAL;
2014 }
2015 }
2016 i = opts.find("min-op-len");
2017 if (i != opts.end()) {
2018 if (rados_sistrtoll(i, &min_op_len)) {
2019 return -EINVAL;
2020 }
2021 }
2022 i = opts.find("max-op-len");
2023 if (i != opts.end()) {
2024 if (rados_sistrtoll(i, &max_op_len)) {
2025 return -EINVAL;
2026 }
2027 }
2028 i = opts.find("max-ops");
2029 if (i != opts.end()) {
2030 if (rados_sistrtoll(i, &max_ops)) {
2031 return -EINVAL;
2032 }
2033 }
2034 i = opts.find("max-backlog");
2035 if (i != opts.end()) {
2036 if (rados_sistrtoll(i, &max_backlog)) {
2037 return -EINVAL;
2038 }
2039 }
2040 i = opts.find("target-throughput");
2041 if (i != opts.end()) {
2042 if (rados_sistrtoll(i, &target_throughput)) {
2043 return -EINVAL;
2044 }
2045 }
2046 i = opts.find("read-percent");
2047 if (i != opts.end()) {
2048 if (rados_sistrtoll(i, &read_percent)) {
2049 return -EINVAL;
2050 }
2051 }
2052 i = opts.find("num-objects");
2053 if (i != opts.end()) {
2054 if (rados_sistrtoll(i, &num_objs)) {
2055 return -EINVAL;
2056 }
2057 }
2058 i = opts.find("run-length");
2059 if (i != opts.end()) {
2060 if (rados_sistrtoll(i, &run_length)) {
2061 return -EINVAL;
2062 }
2063 }
2064 i = opts.find("show-time");
2065 if (i != opts.end()) {
2066 show_time = true;
2067 }
2068 i = opts.find("no-cleanup");
2069 if (i != opts.end()) {
2070 cleanup = false;
2071 }
2072 i = opts.find("no-hints");
2073 if (i != opts.end()) {
2074 hints = false;
2075 }
11fdf7f2
TL
2076 i = opts.find("reuse-bench");
2077 if (i != opts.end()) {
2078 reuse_bench = true;
2079 }
7c673cae
FG
2080 i = opts.find("pretty-format");
2081 if (i != opts.end()) {
2082 pretty_format = true;
2083 }
2084 i = opts.find("format");
2085 if (i != opts.end()) {
2086 const char *format = i->second.c_str();
11fdf7f2 2087 formatter.reset(Formatter::create(format));
7c673cae
FG
2088 if (!formatter) {
2089 cerr << "unrecognized format: " << format << std::endl;
2090 return -EINVAL;
2091 }
2092 }
2093 i = opts.find("namespace");
2094 if (i != opts.end()) {
2095 nspace = i->second;
2096 }
2097 i = opts.find("no-verify");
2098 if (i != opts.end()) {
2099 no_verify = true;
2100 }
2101 i = opts.find("output");
2102 if (i != opts.end()) {
2103 output = i->second.c_str();
2104 }
2105 i = opts.find("write-dest-obj");
2106 if (i != opts.end()) {
2107 bench_write_dest |= static_cast<int>(OP_WRITE_DEST_OBJ);
2108 }
2109 i = opts.find("write-dest-omap");
2110 if (i != opts.end()) {
2111 bench_write_dest |= static_cast<int>(OP_WRITE_DEST_OMAP);
2112 }
2113 i = opts.find("write-dest-xattr");
2114 if (i != opts.end()) {
2115 bench_write_dest |= static_cast<int>(OP_WRITE_DEST_XATTR);
2116 }
2117 i = opts.find("with-clones");
2118 if (i != opts.end()) {
2119 with_clones = true;
2120 }
2121 i = opts.find("omap-key-file");
2122 if (i != opts.end()) {
2123 string err;
2124 bufferlist indata;
2125 ret = indata.read_file(i->second.c_str(), &err);
2126 if (ret < 0) {
2127 cerr << err << std::endl;
2128 return 1;
2129 }
7c673cae 2130 omap_key = std::string(indata.c_str(), indata.length());
f67539c2
TL
2131 }
2132 i = opts.find("obj-name-file");
2133 if (i != opts.end()) {
2134 string err;
2135 bufferlist indata;
2136 ret = indata.read_file(i->second.c_str(), &err);
2137 if (ret < 0) {
2138 cerr << err << std::endl;
2139 return 1;
7c673cae 2140 }
f67539c2 2141 obj_name = std::string(indata.c_str(), indata.length());
7c673cae 2142 }
11fdf7f2
TL
2143 i = opts.find("offset_align");
2144 if (i != opts.end()) {
2145 if (rados_sistrtoll(i, &offset_align)) {
2146 return -EINVAL;
2147 }
2148 }
2149 i = opts.find("with-reference");
2150 if (i != opts.end()) {
2151 with_reference = true;
2152 }
f67539c2
TL
2153 i = opts.find("input_file");
2154 if (i != opts.end()) {
2155 input_file = i->second;
2156 }
11fdf7f2 2157
7c673cae
FG
2158 // open rados
2159 ret = rados.init_with_context(g_ceph_context);
2160 if (ret < 0) {
2161 cerr << "couldn't initialize rados: " << cpp_strerror(ret) << std::endl;
11fdf7f2 2162 return 1;
7c673cae
FG
2163 }
2164
2165 ret = rados.connect();
2166 if (ret) {
2167 cerr << "couldn't connect to cluster: " << cpp_strerror(ret) << std::endl;
11fdf7f2 2168 return 1;
7c673cae
FG
2169 }
2170
2171 if (create_pool && !pool_name) {
2172 cerr << "--create-pool requested but pool_name was not specified!" << std::endl;
11fdf7f2
TL
2173 usage(cerr);
2174 return 1;
7c673cae
FG
2175 }
2176
2177 if (create_pool) {
11fdf7f2 2178 ret = rados.pool_create(pool_name);
7c673cae
FG
2179 if (ret < 0) {
2180 cerr << "error creating pool " << pool_name << ": "
2181 << cpp_strerror(ret) << std::endl;
11fdf7f2 2182 return 1;
7c673cae
FG
2183 }
2184 }
2185
eafe8130
TL
2186 i = opts.find("pgid");
2187 boost::optional<pg_t> pgid(i != opts.end(), pg_t());
2188 if (pgid && (!pgid->parse(i->second.c_str()) || (pool_name && rados.pool_lookup(pool_name) != pgid->pool()))) {
2189 cerr << "invalid pgid" << std::endl;
2190 return 1;
2191 }
2192
7c673cae 2193 // open io context.
11fdf7f2
TL
2194 if (pool_name || pgid) {
2195 ret = pool_name ? rados.ioctx_create(pool_name, io_ctx) : rados.ioctx_create2(pgid->pool(), io_ctx);
7c673cae 2196 if (ret < 0) {
11fdf7f2
TL
2197 cerr << "error opening pool "
2198 << (pool_name ? pool_name : std::string("with id ") + std::to_string(pgid->pool())) << ": "
7c673cae 2199 << cpp_strerror(ret) << std::endl;
11fdf7f2 2200 return 1;
7c673cae
FG
2201 }
2202
2203 // align op_size
2204 {
1e59de90
TL
2205 bool req;
2206 ret = io_ctx.pool_requires_alignment2(&req);
7c673cae
FG
2207 if (ret < 0) {
2208 cerr << "error checking pool alignment requirement"
2209 << cpp_strerror(ret) << std::endl;
11fdf7f2 2210 return 1;
7c673cae
FG
2211 }
2212
1e59de90 2213 if (req) {
7c673cae
FG
2214 uint64_t align = 0;
2215 ret = io_ctx.pool_required_alignment2(&align);
2216 if (ret < 0) {
2217 cerr << "error getting pool alignment"
2218 << cpp_strerror(ret) << std::endl;
11fdf7f2 2219 return 1;
7c673cae
FG
2220 }
2221
2222 const uint64_t prev_op_size = op_size;
2223 op_size = uint64_t((op_size + align - 1) / align) * align;
2224 // Warn: if user specified and it was rounded
2225 if (prev_op_size != default_op_size && prev_op_size != op_size)
2226 cerr << "INFO: op_size has been rounded to " << op_size << std::endl;
2227 }
2228 }
2229
11fdf7f2 2230#ifdef WITH_LIBRADOSSTRIPER
7c673cae
FG
2231 // create striper interface
2232 if (opts.find("striper") != opts.end()) {
11fdf7f2
TL
2233 // Note that this call does a tricky thing by reaching into a "singleton". We count
2234 // on this happening only once:
2235 ret = RadosStriper::striper_create(io_ctx, &detail::striper());
7c673cae 2236 if (0 != ret) {
11fdf7f2
TL
2237 cerr << "error opening pool " << pool_name << " with striper interface: "
2238 << cpp_strerror(ret) << std::endl;
2239 return 1;
7c673cae
FG
2240 }
2241 use_striper = true;
2242 }
11fdf7f2 2243#endif // USE_LIBRADOSSTRIPER
7c673cae
FG
2244 }
2245
2246 // snapname?
2247 if (snapname) {
2248 if (!pool_name) {
2249 cerr << "pool name must be specified with --snap" << std::endl;
11fdf7f2 2250 return 1;
7c673cae
FG
2251 }
2252 ret = io_ctx.snap_lookup(snapname, &snapid);
2253 if (ret < 0) {
2254 cerr << "error looking up snap '" << snapname << "': " << cpp_strerror(ret) << std::endl;
11fdf7f2 2255 return 1;
7c673cae
FG
2256 }
2257 }
2258 if (oloc.size()) {
2259 if (!pool_name) {
f67539c2 2260 cerr << "pool name must be specified with --object-locator" << std::endl;
11fdf7f2 2261 return 1;
7c673cae
FG
2262 }
2263 io_ctx.locator_set_key(oloc);
2264 }
2265 // Use namespace from command line if specified
2266 if (opts.find("namespace") != opts.end()) {
2267 if (!pool_name) {
2268 cerr << "pool name must be specified with --namespace" << std::endl;
11fdf7f2 2269 return 1;
7c673cae
FG
2270 }
2271 io_ctx.set_namespace(nspace);
2272 // Use wildcard if --all specified and --default NOT specified
2273 } else if (opts.find("all") != opts.end() && opts.find("default") == opts.end()) {
2274 // Only the ls should ever set namespace to special value
2275 wildcard = true;
2276 }
2277 if (snapid != CEPH_NOSNAP) {
2278 if (!pool_name) {
2279 cerr << "pool name must be specified with --snapid" << std::endl;
11fdf7f2 2280 return 1;
7c673cae
FG
2281 }
2282 string name;
2283 ret = io_ctx.snap_get_name(snapid, &name);
2284 if (ret < 0) {
2285 cerr << "snapid " << snapid << " doesn't exist in pool "
2286 << io_ctx.get_pool_name() << std::endl;
11fdf7f2 2287 return 1;
7c673cae
FG
2288 }
2289 io_ctx.snap_set_read(snapid);
2290 cout << "selected snap " << snapid << " '" << name << "'" << std::endl;
2291 }
2292
11fdf7f2 2293 ceph_assert(!nargs.empty());
7c673cae
FG
2294
2295 // list pools?
2296 if (strcmp(nargs[0], "lspools") == 0) {
2297 list<string> vec;
2298 ret = rados.pool_list(vec);
2299 if (ret < 0) {
2300 cerr << "error listing pools: " << cpp_strerror(ret) << std::endl;
11fdf7f2 2301 return 1;
7c673cae
FG
2302 }
2303 for (list<string>::iterator i = vec.begin(); i != vec.end(); ++i)
2304 cout << *i << std::endl;
2305 }
2306 else if (strcmp(nargs[0], "df") == 0) {
2307 // pools
2308 list<string> vec;
2309
2310 if (!pool_name) {
2311 ret = rados.pool_list(vec);
2312 if (ret < 0) {
2313 cerr << "error listing pools: " << cpp_strerror(ret) << std::endl;
11fdf7f2 2314 return 1;
7c673cae
FG
2315 }
2316 } else {
2317 vec.push_back(pool_name);
2318 }
2319
2320 map<string,librados::pool_stat_t> stats;
2321 ret = rados.get_pool_stats(vec, stats);
2322 if (ret < 0) {
2323 cerr << "error fetching pool stats: " << cpp_strerror(ret) << std::endl;
11fdf7f2 2324 return 1;
7c673cae
FG
2325 }
2326
2327 TextTable tab;
2328
2329 if (!formatter) {
2330 tab.define_column("POOL_NAME", TextTable::LEFT, TextTable::LEFT);
11fdf7f2
TL
2331 tab.define_column("USED", TextTable::RIGHT, TextTable::RIGHT);
2332 tab.define_column("OBJECTS", TextTable::RIGHT, TextTable::RIGHT);
2333 tab.define_column("CLONES", TextTable::RIGHT, TextTable::RIGHT);
2334 tab.define_column("COPIES", TextTable::RIGHT, TextTable::RIGHT);
2335 tab.define_column("MISSING_ON_PRIMARY", TextTable::RIGHT, TextTable::RIGHT);
2336 tab.define_column("UNFOUND", TextTable::RIGHT, TextTable::RIGHT);
2337 tab.define_column("DEGRADED", TextTable::RIGHT, TextTable::RIGHT);
2338 tab.define_column("RD_OPS", TextTable::RIGHT, TextTable::RIGHT);
2339 tab.define_column("RD", TextTable::RIGHT, TextTable::RIGHT);
2340 tab.define_column("WR_OPS", TextTable::RIGHT, TextTable::RIGHT);
2341 tab.define_column("WR", TextTable::RIGHT, TextTable::RIGHT);
2342 tab.define_column("USED COMPR", TextTable::RIGHT, TextTable::RIGHT);
2343 tab.define_column("UNDER COMPR", TextTable::RIGHT, TextTable::RIGHT);
7c673cae
FG
2344 } else {
2345 formatter->open_object_section("stats");
2346 formatter->open_array_section("pools");
2347 }
2348 for (map<string,librados::pool_stat_t>::iterator i = stats.begin();
2349 i != stats.end();
2350 ++i) {
2351 const char *pool_name = i->first.c_str();
2352 librados::pool_stat_t& s = i->second;
2353 if (!formatter) {
2354 tab << pool_name
1adf2230 2355 << byte_u_t(s.num_bytes)
7c673cae
FG
2356 << s.num_objects
2357 << s.num_object_clones
2358 << s.num_object_copies
2359 << s.num_objects_missing_on_primary
2360 << s.num_objects_unfound
2361 << s.num_objects_degraded
2362 << s.num_rd
1adf2230 2363 << byte_u_t(s.num_rd_kb << 10)
7c673cae 2364 << s.num_wr
1adf2230 2365 << byte_u_t(s.num_wr_kb << 10)
11fdf7f2
TL
2366 << byte_u_t(s.compressed_bytes_alloc)
2367 << byte_u_t(s.compressed_bytes_orig)
7c673cae
FG
2368 << TextTable::endrow;
2369 } else {
2370 formatter->open_object_section("pool");
2371 int64_t pool_id = rados.pool_lookup(pool_name);
2372 formatter->dump_string("name", pool_name);
2373 if (pool_id >= 0)
2374 formatter->dump_int("id", pool_id);
2375 else
2376 cerr << "ERROR: lookup_pg_pool_name for name=" << pool_name
2377 << " returned " << pool_id << std::endl;
2378 formatter->dump_int("size_bytes",s.num_bytes);
2379 formatter->dump_int("size_kb", s.num_kb);
2380 formatter->dump_int("num_objects", s.num_objects);
2381 formatter->dump_int("num_object_clones", s.num_object_clones);
2382 formatter->dump_int("num_object_copies", s.num_object_copies);
2383 formatter->dump_int("num_objects_missing_on_primary", s.num_objects_missing_on_primary);
2384 formatter->dump_int("num_objects_unfound", s.num_objects_unfound);
2385 formatter->dump_int("num_objects_degraded", s.num_objects_degraded);
2386 formatter->dump_int("read_ops", s.num_rd);
2387 formatter->dump_int("read_bytes", s.num_rd_kb * 1024ull);
2388 formatter->dump_int("write_ops", s.num_wr);
2389 formatter->dump_int("write_bytes", s.num_wr_kb * 1024ull);
11fdf7f2
TL
2390 formatter->dump_int("compress_bytes_used", s.compressed_bytes_alloc);
2391 formatter->dump_int("compress_under_bytes", s.compressed_bytes_orig);
7c673cae
FG
2392 formatter->close_section();
2393 }
2394 }
2395
2396 if (!formatter) {
2397 cout << tab;
2398 }
2399
2400 // total
2401 cluster_stat_t tstats;
2402 ret = rados.cluster_stat(tstats);
2403 if (ret < 0) {
2404 cerr << "error getting total cluster usage: " << cpp_strerror(ret) << std::endl;
11fdf7f2 2405 return 1;
7c673cae
FG
2406 }
2407 if (!formatter) {
2408 cout << std::endl;
2409 cout << "total_objects " << tstats.num_objects
2410 << std::endl;
1adf2230 2411 cout << "total_used " << byte_u_t(tstats.kb_used << 10)
7c673cae 2412 << std::endl;
1adf2230 2413 cout << "total_avail " << byte_u_t(tstats.kb_avail << 10)
7c673cae 2414 << std::endl;
1adf2230 2415 cout << "total_space " << byte_u_t(tstats.kb << 10)
7c673cae
FG
2416 << std::endl;
2417 } else {
2418 formatter->close_section();
2419 formatter->dump_int("total_objects", tstats.num_objects);
2420 formatter->dump_int("total_used", tstats.kb_used);
2421 formatter->dump_int("total_avail", tstats.kb_avail);
2422 formatter->dump_int("total_space", tstats.kb);
2423 formatter->close_section();
2424 formatter->flush(cout);
2425 }
2426 }
2427
2428 else if (strcmp(nargs[0], "ls") == 0) {
11fdf7f2
TL
2429 if (!pool_name && !pgid) {
2430 cerr << "either pool name or pg id needs to be specified" << std::endl;
2431 return 1;
7c673cae
FG
2432 }
2433
f91f0fd5 2434 if (wildcard) {
7c673cae 2435 io_ctx.set_namespace(all_nspaces);
f91f0fd5 2436 }
11fdf7f2
TL
2437 bool use_stdout = (!output && (nargs.size() < 2 || (strcmp(nargs[1], "-") == 0)));
2438 if (!use_stdout && !output) {
2439 cerr << "Please use --output to specify the output file name" << std::endl;
2440 return 1;
2441 }
f91f0fd5 2442
7c673cae 2443 ostream *outstream;
f91f0fd5 2444 if (use_stdout) {
7c673cae 2445 outstream = &cout;
f91f0fd5 2446 } else {
11fdf7f2 2447 outstream = new ofstream(output);
f91f0fd5 2448 }
7c673cae
FG
2449
2450 {
f91f0fd5 2451 if (formatter) {
7c673cae 2452 formatter->open_array_section("objects");
f91f0fd5 2453 }
7c673cae 2454 try {
11fdf7f2 2455 librados::NObjectIterator i = pgid ? io_ctx.nobjects_begin(pgid->ps()) : io_ctx.nobjects_begin();
f91f0fd5 2456 const librados::NObjectIterator i_end = io_ctx.nobjects_end();
7c673cae 2457 for (; i != i_end; ++i) {
11fdf7f2 2458#ifdef WITH_LIBRADOSSTRIPER
7c673cae
FG
2459 if (use_striper) {
2460 // in case of --striper option, we only list striped
2461 // objects, so we only display the first object of
2462 // each, without its suffix '.000...000'
2463 size_t l = i->get_oid().length();
2464 if (l <= 17 ||
f91f0fd5
TL
2465 (0 != i->get_oid().compare(l-17, 17,".0000000000000000"))) {
2466 continue;
2467 }
7c673cae 2468 }
11fdf7f2
TL
2469#endif // WITH_LIBRADOSSTRIPER
2470 if (pgid) {
2471 uint32_t ps;
f91f0fd5 2472 if (io_ctx.get_object_pg_hash_position2(i->get_oid(), &ps) || pgid->ps() != ps) {
11fdf7f2 2473 break;
f91f0fd5 2474 }
11fdf7f2 2475 }
7c673cae
FG
2476 if (!formatter) {
2477 // Only include namespace in output when wildcard specified
f91f0fd5 2478 if (wildcard) {
7c673cae 2479 *outstream << i->get_nspace() << "\t";
f91f0fd5
TL
2480 }
2481 *outstream << detail::get_oid(i, use_striper);
2482 if (i->get_locator().size()) {
7c673cae 2483 *outstream << "\t" << i->get_locator();
f91f0fd5 2484 }
7c673cae
FG
2485 *outstream << std::endl;
2486 } else {
2487 formatter->open_object_section("object");
2488 formatter->dump_string("namespace", i->get_nspace());
11fdf7f2 2489
f91f0fd5 2490 detail::dump_name(formatter.get(), i, use_striper);
11fdf7f2 2491
f91f0fd5 2492 if (i->get_locator().size()) {
7c673cae 2493 formatter->dump_string("locator", i->get_locator());
f91f0fd5 2494 }
7c673cae 2495 formatter->close_section(); //object
f91f0fd5
TL
2496
2497 constexpr int TARGET_BYTES_PER_FLUSH = 4096;
2498 if (formatter->get_len() >= TARGET_BYTES_PER_FLUSH) {
2499 formatter->flush(*outstream);
2500 }
7c673cae
FG
2501 }
2502 }
2503 }
f64942e4 2504 catch (const std::exception& e) {
7c673cae 2505 cerr << e.what() << std::endl;
11fdf7f2 2506 return 1;
7c673cae
FG
2507 }
2508 }
2509 if (formatter) {
2510 formatter->close_section(); //objects
2511 formatter->flush(*outstream);
f91f0fd5 2512 if (pretty_format) {
7c673cae 2513 *outstream << std::endl;
f91f0fd5 2514 }
7c673cae
FG
2515 formatter->flush(*outstream);
2516 }
f91f0fd5 2517 if (!stdout) {
7c673cae 2518 delete outstream;
f91f0fd5 2519 }
7c673cae 2520 }
7c673cae 2521 else if (strcmp(nargs[0], "mapext") == 0) {
f67539c2 2522 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2523 usage(cerr);
2524 return 1;
2525 }
f67539c2
TL
2526 if (!obj_name) {
2527 obj_name = nargs[1];
2528 }
7c673cae 2529 std::map<uint64_t,uint64_t> m;
f67539c2 2530 ret = io_ctx.mapext(*obj_name, 0, -1, m);
7c673cae 2531 if (ret < 0) {
f67539c2 2532 cerr << "mapext error on " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2533 return 1;
7c673cae
FG
2534 }
2535 std::map<uint64_t,uint64_t>::iterator iter;
2536 for (iter = m.begin(); iter != m.end(); ++iter) {
2537 cout << hex << iter->first << "\t" << iter->second << dec << std::endl;
2538 }
2539 }
2540 else if (strcmp(nargs[0], "stat") == 0) {
f67539c2 2541 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2542 usage(cerr);
2543 return 1;
2544 }
f67539c2
TL
2545 if (!obj_name) {
2546 obj_name = nargs[1];
2547 }
7c673cae
FG
2548 uint64_t size;
2549 time_t mtime;
11fdf7f2 2550
f67539c2 2551 ret = detail::stat(io_ctx, *obj_name, size, mtime, use_striper);
11fdf7f2 2552
7c673cae 2553 if (ret < 0) {
f67539c2 2554 cerr << " error stat-ing " << pool_name << "/" << prettify(*obj_name) << ": "
7c673cae 2555 << cpp_strerror(ret) << std::endl;
11fdf7f2 2556 return 1;
7c673cae
FG
2557 } else {
2558 utime_t t(mtime, 0);
f67539c2 2559 cout << pool_name << "/" << prettify(*obj_name)
7c673cae
FG
2560 << " mtime " << t << ", size " << size << std::endl;
2561 }
2562 }
11fdf7f2 2563 else if (strcmp(nargs[0], "stat2") == 0) {
f67539c2 2564 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2565 usage(cerr);
2566 return 1;
2567 }
f67539c2
TL
2568 if (!obj_name) {
2569 obj_name = nargs[1];
2570 }
11fdf7f2
TL
2571 uint64_t size;
2572 struct timespec mtime;
2573
f67539c2 2574 ret = detail::stat2(io_ctx, *obj_name, size, mtime, use_striper);
11fdf7f2
TL
2575
2576 if (ret < 0) {
f67539c2 2577 cerr << " error stat-ing " << pool_name << "/" << prettify(*obj_name) << ": "
11fdf7f2
TL
2578 << cpp_strerror(ret) << std::endl;
2579 return 1;
2580 } else {
2581 utime_t t(mtime);
f67539c2 2582 cout << pool_name << "/" << prettify(*obj_name)
11fdf7f2
TL
2583 << " mtime " << t << ", size " << size << std::endl;
2584 }
2585 }
2586 else if (strcmp(nargs[0], "touch") == 0) {
f67539c2 2587 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2588 usage(cerr);
2589 return 1;
2590 }
11fdf7f2 2591 time_t timestamp = time(NULL);
f67539c2 2592 if (nargs.size() > (obj_name ? 1 : 2)) {
11fdf7f2 2593 char* endptr = NULL;
f67539c2 2594 timestamp = static_cast<time_t>(strtoll(nargs[obj_name ? 1 : 2], &endptr, 10));
11fdf7f2 2595 if (*endptr) {
f67539c2 2596 cerr << "Invalid value for timestamp: '" << nargs[obj_name ? 1 : 2] << "'" << std::endl;
11fdf7f2
TL
2597 ret = -EINVAL;
2598 return 1;
2599 }
2600 }
f67539c2
TL
2601 if (!obj_name) {
2602 obj_name = nargs[1];
2603 }
11fdf7f2
TL
2604 ObjectWriteOperation op;
2605 op.create(false);
2606 op.mtime(&timestamp);
f67539c2 2607 ret = io_ctx.operate(*obj_name, &op);
11fdf7f2 2608 if (ret < 0) {
f67539c2 2609 cerr << " error touch-ing " << pool_name << "/" << prettify(*obj_name) << ": "
11fdf7f2
TL
2610 << cpp_strerror(ret) << std::endl;
2611 return 1;
2612 }
2613 }
7c673cae 2614 else if (strcmp(nargs[0], "get") == 0) {
f67539c2 2615 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2616 usage(cerr);
2617 return 1;
2618 }
f67539c2
TL
2619 const char* out_filename;
2620 if (obj_name) {
2621 out_filename = nargs[1];
2622 } else {
2623 obj_name = nargs[1];
2624 out_filename = nargs[2];
2625 }
2626 ret = do_get(io_ctx, *obj_name, out_filename, op_size, use_striper);
7c673cae 2627 if (ret < 0) {
f67539c2 2628 cerr << "error getting " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2629 return 1;
7c673cae
FG
2630 }
2631 }
2632 else if (strcmp(nargs[0], "put") == 0) {
f67539c2 2633 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2634 usage(cerr);
2635 return 1;
2636 }
f67539c2
TL
2637 const char* in_filename;
2638 if (obj_name) {
2639 in_filename = nargs[1];
2640 } else {
2641 obj_name = nargs[1];
2642 in_filename = nargs[2];
2643 }
9f95a23c 2644 bool create_object = !obj_offset_specified;
f67539c2 2645 ret = do_put(io_ctx, *obj_name, in_filename, op_size, obj_offset, create_object, use_striper);
7c673cae 2646 if (ret < 0) {
f67539c2 2647 cerr << "error putting " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2648 return 1;
7c673cae
FG
2649 }
2650 }
2651 else if (strcmp(nargs[0], "append") == 0) {
f67539c2 2652 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2653 usage(cerr);
2654 return 1;
2655 }
f67539c2
TL
2656 const char* in_filename;
2657 if (obj_name) {
2658 in_filename = nargs[1];
2659 } else {
2660 obj_name = nargs[1];
2661 in_filename = nargs[2];
2662 }
2663 ret = do_append(io_ctx, *obj_name, in_filename, op_size, use_striper);
7c673cae 2664 if (ret < 0) {
f67539c2 2665 cerr << "error appending " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2666 return 1;
7c673cae
FG
2667 }
2668 }
2669 else if (strcmp(nargs[0], "truncate") == 0) {
f67539c2 2670 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2671 usage(cerr);
2672 return 1;
2673 }
7c673cae 2674
7c673cae 2675 char* endptr = NULL;
f67539c2
TL
2676 long size;
2677 if (!obj_name) {
2678 obj_name = nargs[1];
2679 size = strtoll(nargs[2], &endptr, 10);
2680 } else {
2681 size = strtoll(nargs[1], &endptr, 10);
2682 }
7c673cae
FG
2683 if (*endptr) {
2684 cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
2685 ret = -EINVAL;
11fdf7f2 2686 return 1;
7c673cae
FG
2687 }
2688 if (size < 0) {
2689 cerr << "error, cannot truncate to negative value" << std::endl;
11fdf7f2
TL
2690 usage(cerr);
2691 return 1;
7c673cae 2692 }
11fdf7f2 2693
f67539c2 2694 ret = detail::trunc(io_ctx, *obj_name, size, use_striper);
11fdf7f2 2695
7c673cae
FG
2696 if (ret < 0) {
2697 cerr << "error truncating oid "
f67539c2 2698 << prettify(*obj_name) << " to " << size << ": "
7c673cae
FG
2699 << cpp_strerror(ret) << std::endl;
2700 } else {
2701 ret = 0;
2702 }
2703 }
2704 else if (strcmp(nargs[0], "setxattr") == 0) {
f67539c2
TL
2705 if (!pool_name || nargs.size() < (obj_name ? 2 : 3) ||
2706 nargs.size() > (obj_name ? 3 : 4)) {
11fdf7f2
TL
2707 usage(cerr);
2708 return 1;
2709 }
f67539c2 2710 string attr_name(nargs[obj_name ? 1 : 2]);
7c673cae 2711 bufferlist bl;
f67539c2
TL
2712 if (nargs.size() == (obj_name ? 3 : 4)) {
2713 string attr_val(nargs[obj_name ? 2 : 3]);
7c673cae
FG
2714 bl.append(attr_val.c_str(), attr_val.length());
2715 } else {
2716 do {
2717 ret = bl.read_fd(STDIN_FILENO, 1024); // from stdin
2718 if (ret < 0)
11fdf7f2 2719 return 1;
7c673cae
FG
2720 } while (ret > 0);
2721 }
f67539c2
TL
2722 if (!obj_name) {
2723 obj_name = nargs[1];
2724 }
7c673cae 2725
f67539c2 2726 ret = detail::setxattr(io_ctx, *obj_name, attr_name, bl, use_striper);
11fdf7f2 2727
7c673cae 2728 if (ret < 0) {
f67539c2 2729 cerr << "error setting xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2730 return 1;
7c673cae
FG
2731 }
2732 else
2733 ret = 0;
2734 }
2735 else if (strcmp(nargs[0], "getxattr") == 0) {
f67539c2 2736 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2737 usage(cerr);
2738 return 1;
2739 }
f67539c2
TL
2740 string attr_name(nargs[obj_name ? 1 : 2]);
2741 if (!obj_name) {
2742 obj_name = nargs[1];
2743 }
7c673cae 2744 bufferlist bl;
f67539c2 2745 ret = detail::getxattr(io_ctx, *obj_name, attr_name, bl, use_striper);
11fdf7f2 2746
7c673cae 2747 if (ret < 0) {
f67539c2 2748 cerr << "error getting xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2749 return 1;
7c673cae
FG
2750 }
2751 else
2752 ret = 0;
2753 string s(bl.c_str(), bl.length());
2754 cout << s;
2755 } else if (strcmp(nargs[0], "rmxattr") == 0) {
f67539c2 2756 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2757 usage(cerr);
2758 return 1;
2759 }
7c673cae 2760
f67539c2
TL
2761 string attr_name(nargs[obj_name ? 1 : 2]);
2762 if (!obj_name) {
2763 obj_name = nargs[1];
2764 }
2765 ret = detail::rmxattr(io_ctx, *obj_name, attr_name, use_striper);
11fdf7f2 2766
7c673cae 2767 if (ret < 0) {
f67539c2 2768 cerr << "error removing xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2769 return 1;
7c673cae
FG
2770 }
2771 } else if (strcmp(nargs[0], "listxattr") == 0) {
f67539c2 2772 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2773 usage(cerr);
2774 return 1;
2775 }
f67539c2
TL
2776 if (!obj_name) {
2777 obj_name = nargs[1];
2778 }
7c673cae 2779 bufferlist bl;
11fdf7f2
TL
2780 map<std::string, bufferlist> attrset;
2781
f67539c2 2782 ret = detail::getxattrs(io_ctx, *obj_name, attrset, use_striper);
11fdf7f2 2783
7c673cae 2784 if (ret < 0) {
f67539c2 2785 cerr << "error getting xattr set " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2786 return 1;
7c673cae
FG
2787 }
2788
2789 for (map<std::string, bufferlist>::iterator iter = attrset.begin();
2790 iter != attrset.end(); ++iter) {
2791 cout << iter->first << std::endl;
2792 }
2793 } else if (strcmp(nargs[0], "getomapheader") == 0) {
f67539c2 2794 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2795 usage(cerr);
2796 return 1;
2797 }
7c673cae 2798 string outfile;
f67539c2
TL
2799 if (nargs.size() >= (obj_name ? 2 : 3)) {
2800 outfile = nargs[obj_name ? 1 : 2];
2801 }
2802 if (!obj_name) {
2803 obj_name = nargs[1];
7c673cae 2804 }
7c673cae 2805 bufferlist header;
f67539c2 2806 ret = io_ctx.omap_get_header(*obj_name, &header);
7c673cae 2807 if (ret < 0) {
f67539c2 2808 cerr << "error getting omap header " << pool_name << "/" << prettify(*obj_name)
7c673cae 2809 << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2810 return 1;
7c673cae
FG
2811 } else {
2812 if (!outfile.empty()) {
2813 cerr << "Writing to " << outfile << std::endl;
2814 dump_data(outfile, header);
2815 } else {
2816 cout << "header (" << header.length() << " bytes) :\n";
2817 header.hexdump(cout);
2818 cout << std::endl;
2819 }
2820 ret = 0;
2821 }
2822 } else if (strcmp(nargs[0], "setomapheader") == 0) {
f67539c2 2823 if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
11fdf7f2
TL
2824 usage(cerr);
2825 return 1;
2826 }
7c673cae 2827
7c673cae 2828 bufferlist bl;
f67539c2
TL
2829 if (!obj_name) {
2830 obj_name = nargs[1];
2831 bl.append(nargs[2]); // val
2832 } else {
2833 bl.append(nargs[1]); // val
2834 }
2835 ret = io_ctx.omap_set_header(*obj_name, bl);
7c673cae 2836 if (ret < 0) {
f67539c2 2837 cerr << "error setting omap value " << pool_name << "/" << prettify(*obj_name)
7c673cae 2838 << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2839 return 1;
7c673cae
FG
2840 } else {
2841 ret = 0;
2842 }
2843 } else if (strcmp(nargs[0], "setomapval") == 0) {
f67539c2 2844 uint32_t min_args = (omap_key ? 2 : 3);
7c673cae 2845 if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) {
11fdf7f2
TL
2846 usage(cerr);
2847 return 1;
7c673cae
FG
2848 }
2849
2850 string oid(nargs[1]);
f67539c2 2851 if (!omap_key) {
7c673cae 2852 omap_key = nargs[2];
7c673cae
FG
2853 }
2854
2855 bufferlist bl;
f67539c2
TL
2856 if (!input_file.empty()) {
2857 string err;
2858 ret = bl.read_file(input_file.c_str(), &err);
2859 if (ret < 0) {
2860 cerr << "error reading file " << input_file.c_str() << ": " << err << std::endl;
2861 return 1;
2862 }
2863 } else if (nargs.size() > min_args) {
7c673cae
FG
2864 string val(nargs[min_args]);
2865 bl.append(val);
2866 } else {
2867 do {
2868 ret = bl.read_fd(STDIN_FILENO, 1024); // from stdin
2869 if (ret < 0) {
11fdf7f2 2870 return 1;
7c673cae
FG
2871 }
2872 } while (ret > 0);
2873 }
2874
2875 map<string, bufferlist> values;
f67539c2 2876 values[*omap_key] = bl;
7c673cae
FG
2877
2878 ret = io_ctx.omap_set(oid, values);
2879 if (ret < 0) {
2880 cerr << "error setting omap value " << pool_name << "/" << oid << "/"
f67539c2 2881 << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2882 return 1;
7c673cae
FG
2883 } else {
2884 ret = 0;
2885 }
2886 } else if (strcmp(nargs[0], "getomapval") == 0) {
f67539c2
TL
2887 uint32_t min_args = (omap_key ? (obj_name ? 1 : 2)
2888 : (obj_name ? 2 : 3));
7c673cae 2889 if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) {
11fdf7f2
TL
2890 usage(cerr);
2891 return 1;
7c673cae
FG
2892 }
2893
f67539c2
TL
2894 if (!omap_key) {
2895 omap_key = nargs[obj_name ? 1 : 2];
7c673cae
FG
2896 }
2897
2898 set<string> keys;
f67539c2 2899 keys.insert(*omap_key);
7c673cae
FG
2900
2901 std::string outfile;
2902 if (nargs.size() > min_args) {
2903 outfile = nargs[min_args];
2904 }
f67539c2
TL
2905 if (!obj_name) {
2906 obj_name = nargs[1];
2907 }
7c673cae
FG
2908
2909 map<string, bufferlist> values;
f67539c2 2910 ret = io_ctx.omap_get_vals_by_keys(*obj_name, keys, &values);
7c673cae 2911 if (ret < 0) {
f67539c2
TL
2912 cerr << "error getting omap value " << pool_name << "/" << prettify(*obj_name) << "/"
2913 << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2914 return 1;
7c673cae
FG
2915 } else {
2916 ret = 0;
2917 }
2918
f67539c2 2919 if (values.size() && values.begin()->first == *omap_key) {
7c673cae
FG
2920 if (!outfile.empty()) {
2921 cerr << "Writing to " << outfile << std::endl;
2922 dump_data(outfile, values.begin()->second);
2923 } else {
2924 cout << "value (" << values.begin()->second.length() << " bytes) :\n";
2925 values.begin()->second.hexdump(cout);
2926 cout << std::endl;
2927 }
2928 ret = 0;
2929 } else {
f67539c2
TL
2930 cout << "No such key: " << pool_name << "/" << prettify(*obj_name) << "/"
2931 << prettify(*omap_key) << std::endl;
11fdf7f2 2932 return 1;
7c673cae
FG
2933 }
2934 } else if (strcmp(nargs[0], "rmomapkey") == 0) {
f67539c2
TL
2935 uint32_t num_args = (omap_key ? (obj_name ? 1 : 2)
2936 : (obj_name ? 2 : 3));
7c673cae 2937 if (!pool_name || nargs.size() != num_args) {
11fdf7f2
TL
2938 usage(cerr);
2939 return 1;
7c673cae
FG
2940 }
2941
f67539c2
TL
2942 if (!omap_key) {
2943 omap_key = nargs[obj_name ? 1 : 2];
2944 }
2945 if (!obj_name) {
2946 obj_name = nargs[1];
7c673cae
FG
2947 }
2948 set<string> keys;
f67539c2 2949 keys.insert(*omap_key);
7c673cae 2950
f67539c2 2951 ret = io_ctx.omap_rm_keys(*obj_name, keys);
7c673cae 2952 if (ret < 0) {
f67539c2
TL
2953 cerr << "error removing omap key " << pool_name << "/" << prettify(*obj_name) << "/"
2954 << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 2955 return 1;
7c673cae
FG
2956 } else {
2957 ret = 0;
2958 }
11fdf7f2 2959 } else if (strcmp(nargs[0], "clearomap") == 0) {
f67539c2 2960 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2961 usage(cerr);
2962 return 1;
2963 }
f67539c2
TL
2964 // strip nargs[0] which is "clearomap"
2965 std::vector<std::string> oids(std::next(std::begin(nargs)),
2966 std::end(nargs));
2967 if (obj_name) {
2968 oids.push_back(*obj_name);
2969 }
11fdf7f2 2970
f67539c2 2971 for (const auto& oid : oids) {
11fdf7f2
TL
2972 ret = io_ctx.omap_clear(oid);
2973 if (ret < 0) {
f67539c2 2974 cerr << "error clearing omap keys " << pool_name << "/" << prettify(*obj_name) << "/"
11fdf7f2
TL
2975 << cpp_strerror(ret) << std::endl;
2976 return 1;
2977 }
2978 }
2979 ret = 0;
7c673cae 2980 } else if (strcmp(nargs[0], "listomapvals") == 0) {
f67539c2 2981 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
2982 usage(cerr);
2983 return 1;
2984 }
f67539c2
TL
2985 if (!obj_name) {
2986 obj_name = nargs[1];
2987 }
7c673cae 2988 string last_read = "";
7c673cae
FG
2989 do {
2990 map<string, bufferlist> values;
f67539c2 2991 ret = io_ctx.omap_get_vals(*obj_name, last_read, MAX_OMAP_BYTES_PER_REQUEST, &values);
7c673cae 2992 if (ret < 0) {
f67539c2 2993 cerr << "error getting omap keys " << pool_name << "/" << prettify(*obj_name) << ": "
7c673cae
FG
2994 << cpp_strerror(ret) << std::endl;
2995 return 1;
2996 }
2997 ret = values.size();
2998 for (map<string, bufferlist>::const_iterator it = values.begin();
2999 it != values.end(); ++it) {
3000 last_read = it->first;
3001 // dump key in hex if it contains nonprintable characters
3002 if (std::count_if(it->first.begin(), it->first.end(),
3003 (int (*)(int))isprint) < (int)it->first.length()) {
3004 cout << "key (" << it->first.length() << " bytes):\n";
3005 bufferlist keybl;
3006 keybl.append(it->first);
3007 keybl.hexdump(cout);
3008 } else {
3009 cout << it->first;
3010 }
3011 cout << std::endl;
3012 cout << "value (" << it->second.length() << " bytes) :\n";
3013 it->second.hexdump(cout);
3014 cout << std::endl;
3015 }
9f95a23c 3016 } while (ret == MAX_OMAP_BYTES_PER_REQUEST);
7c673cae
FG
3017 ret = 0;
3018 }
3019 else if (strcmp(nargs[0], "cp") == 0) {
f67539c2 3020 // XXX: binary names aren't supported for this operation
11fdf7f2
TL
3021 if (!pool_name) {
3022 usage(cerr);
3023 return 1;
3024 }
7c673cae 3025
11fdf7f2
TL
3026 if (nargs.size() < 2 || nargs.size() > 3) {
3027 usage(cerr);
3028 return 1;
3029 }
7c673cae
FG
3030
3031 const char *target = target_pool_name;
3032 if (!target)
3033 target = pool_name;
3034
3035 const char *target_obj;
3036 if (nargs.size() < 3) {
3037 if (strcmp(target, pool_name) == 0) {
3038 cerr << "cannot copy object into itself" << std::endl;
11fdf7f2 3039 return 1;
7c673cae
FG
3040 }
3041 target_obj = nargs[1];
3042 } else {
3043 target_obj = nargs[2];
3044 }
3045
3046 // open io context.
3047 IoCtx target_ctx;
3048 ret = rados.ioctx_create(target, target_ctx);
3049 if (ret < 0) {
3050 cerr << "error opening target pool " << target << ": "
3051 << cpp_strerror(ret) << std::endl;
11fdf7f2 3052 return 1;
7c673cae
FG
3053 }
3054 if (target_oloc.size()) {
3055 target_ctx.locator_set_key(target_oloc);
3056 }
3057 if (target_nspace.size()) {
3058 target_ctx.set_namespace(target_nspace);
3059 }
3060
3061 ret = do_copy(io_ctx, nargs[1], target_ctx, target_obj);
3062 if (ret < 0) {
3063 cerr << "error copying " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 3064 return 1;
7c673cae
FG
3065 }
3066 } else if (strcmp(nargs[0], "rm") == 0) {
f67539c2 3067 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3068 usage(cerr);
3069 return 1;
3070 }
f67539c2
TL
3071 // strip nargs[0] which is "rm"
3072 std::vector<std::string> oids(std::next(std::begin(nargs)),
3073 std::end(nargs));
3074 if (obj_name) {
3075 oids.push_back(*obj_name);
11fdf7f2 3076 }
f67539c2
TL
3077 for (const auto& oid : oids) {
3078 if (forcefull) {
3079 ret = detail::remove(io_ctx, oid, (CEPH_OSD_FLAG_FULL_FORCE |
3080 CEPH_OSD_FLAG_FULL_TRY), use_striper);
3081 } else {
3082 ret = detail::remove(io_ctx, oid, use_striper);
3083 }
11fdf7f2 3084
f67539c2
TL
3085 if (ret < 0) {
3086 string name = (nspace.size() ? nspace + "/" : "" ) + prettify(oid);
3087 cerr << "error removing " << pool_name << ">" << name << ": " << cpp_strerror(ret) << std::endl;
3088 return 1;
7c673cae
FG
3089 }
3090 }
3091 }
3092 else if (strcmp(nargs[0], "create") == 0) {
f67539c2 3093 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3094 usage(cerr);
3095 return 1;
3096 }
f67539c2
TL
3097 if (!obj_name) {
3098 obj_name = nargs[1];
3099 }
3100 ret = io_ctx.create(*obj_name, true);
7c673cae 3101 if (ret < 0) {
f67539c2 3102 cerr << "error creating " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 3103 return 1;
7c673cae 3104 }
7c673cae
FG
3105 }
3106 else if (strcmp(nargs[0], "cppool") == 0) {
3107 bool force = nargs.size() == 4 && !strcmp(nargs[3], "--yes-i-really-mean-it");
11fdf7f2
TL
3108 if (nargs.size() != 3 && !(nargs.size() == 4 && force)) {
3109 usage(cerr);
3110 return 1;
3111 }
7c673cae
FG
3112 const char *src_pool = nargs[1];
3113 const char *target_pool = nargs[2];
3114
3115 if (strcmp(src_pool, target_pool) == 0) {
3116 cerr << "cannot copy pool into itself" << std::endl;
11fdf7f2 3117 return 1;
7c673cae
FG
3118 }
3119
3120 cerr << "WARNING: pool copy does not preserve user_version, which some "
1e59de90 3121 << "apps may rely on." << std::endl;
7c673cae
FG
3122
3123 if (rados.get_pool_is_selfmanaged_snaps_mode(src_pool)) {
3124 cerr << "WARNING: pool " << src_pool << " has selfmanaged snaps, which are not preserved\n"
3125 << " by the cppool operation. This will break any snapshot user."
3126 << std::endl;
3127 if (!force) {
3128 cerr << " If you insist on making a broken copy, you can pass\n"
3129 << " --yes-i-really-mean-it to proceed anyway."
3130 << std::endl;
3131 exit(1);
3132 }
3133 }
3134
3135 ret = do_copy_pool(rados, src_pool, target_pool);
3136 if (ret < 0) {
3137 cerr << "error copying pool " << src_pool << " => " << target_pool << ": "
3138 << cpp_strerror(ret) << std::endl;
11fdf7f2 3139 return 1;
7c673cae
FG
3140 }
3141 cout << "successfully copied pool " << nargs[1] << std::endl;
3142 }
7c673cae 3143 else if (strcmp(nargs[0], "purge") == 0) {
11fdf7f2
TL
3144 if (nargs.size() < 2) {
3145 usage(cerr);
3146 return 1;
3147 }
7c673cae
FG
3148 if (nargs.size() < 3 ||
3149 strcmp(nargs[2], "--yes-i-really-really-mean-it") != 0) {
3150 cerr << "WARNING:\n"
3151 << " This will PERMANENTLY DESTROY all objects from a pool with no way back.\n"
3152 << " To confirm, follow pool with --yes-i-really-really-mean-it" << std::endl;
11fdf7f2 3153 return 1;
7c673cae
FG
3154 }
3155 ret = rados.ioctx_create(nargs[1], io_ctx);
3156 if (ret < 0) {
3157 cerr << "error pool " << nargs[1] << ": "
3158 << cpp_strerror(ret) << std::endl;
11fdf7f2 3159 return 1;
7c673cae
FG
3160 }
3161 io_ctx.set_namespace(all_nspaces);
9f95a23c 3162 io_ctx.set_pool_full_try();
7c673cae
FG
3163 RadosBencher bencher(g_ceph_context, rados, io_ctx);
3164 ret = bencher.clean_up_slow("", concurrent_ios);
3165 if (ret >= 0) {
3166 cout << "successfully purged pool " << nargs[1] << std::endl;
3167 } else { //error
3168 cerr << "pool " << nargs[1] << " could not be purged" << std::endl;
3169 cerr << "Check your monitor configuration - `mon allow pool delete` is set to false by default,"
3170 << " change it to true to allow deletion of pools" << std::endl;
3171 }
3172 }
3173 else if (strcmp(nargs[0], "lssnap") == 0) {
11fdf7f2
TL
3174 if (!pool_name || nargs.size() != 1) {
3175 usage(cerr);
3176 return 1;
3177 }
7c673cae
FG
3178
3179 vector<snap_t> snaps;
3180 io_ctx.snap_list(&snaps);
3181 for (vector<snap_t>::iterator i = snaps.begin();
3182 i != snaps.end();
3183 ++i) {
3184 string s;
3185 time_t t;
3186 if (io_ctx.snap_get_name(*i, &s) < 0)
3187 continue;
3188 if (io_ctx.snap_get_stamp(*i, &t) < 0)
3189 continue;
3190 struct tm bdt;
3191 localtime_r(&t, &bdt);
3192 cout << *i << "\t" << s << "\t";
3193
3194 std::ios_base::fmtflags original_flags = cout.flags();
3195 cout.setf(std::ios::right);
3196 cout.fill('0');
3197 cout << std::setw(4) << (bdt.tm_year+1900)
3198 << '.' << std::setw(2) << (bdt.tm_mon+1)
3199 << '.' << std::setw(2) << bdt.tm_mday
3200 << ' '
3201 << std::setw(2) << bdt.tm_hour
3202 << ':' << std::setw(2) << bdt.tm_min
3203 << ':' << std::setw(2) << bdt.tm_sec
3204 << std::endl;
3205 cout.flags(original_flags);
3206 }
3207 cout << snaps.size() << " snaps" << std::endl;
3208 }
3209
3210 else if (strcmp(nargs[0], "mksnap") == 0) {
11fdf7f2
TL
3211 if (!pool_name || nargs.size() < 2) {
3212 usage(cerr);
3213 return 1;
3214 }
3215
3216 if (rados.get_pool_is_selfmanaged_snaps_mode(pool_name)) {
3217 cerr << "can't create snapshot: pool " << pool_name
3218 << " is in selfmanaged snaps mode" << std::endl;
3219 return 1;
3220 }
7c673cae
FG
3221
3222 ret = io_ctx.snap_create(nargs[1]);
3223 if (ret < 0) {
3224 cerr << "error creating pool " << pool_name << " snapshot " << nargs[1]
3225 << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 3226 return 1;
7c673cae
FG
3227 }
3228 cout << "created pool " << pool_name << " snap " << nargs[1] << std::endl;
3229 }
3230
3231 else if (strcmp(nargs[0], "rmsnap") == 0) {
11fdf7f2
TL
3232 if (!pool_name || nargs.size() < 2) {
3233 usage(cerr);
3234 return 1;
3235 }
7c673cae
FG
3236
3237 ret = io_ctx.snap_remove(nargs[1]);
3238 if (ret < 0) {
3239 cerr << "error removing pool " << pool_name << " snapshot " << nargs[1]
3240 << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 3241 return 1;
7c673cae
FG
3242 }
3243 cout << "removed pool " << pool_name << " snap " << nargs[1] << std::endl;
3244 }
3245
3246 else if (strcmp(nargs[0], "rollback") == 0) {
11fdf7f2
TL
3247 if (!pool_name || nargs.size() < 3) {
3248 usage(cerr);
3249 return 1;
3250 }
7c673cae
FG
3251
3252 ret = io_ctx.snap_rollback(nargs[1], nargs[2]);
3253 if (ret < 0) {
3254 cerr << "error rolling back pool " << pool_name << " to snapshot " << nargs[1]
3255 << cpp_strerror(ret) << std::endl;
11fdf7f2 3256 return 1;
7c673cae
FG
3257 }
3258 cout << "rolled back pool " << pool_name
3259 << " to snapshot " << nargs[2] << std::endl;
3260 }
3261 else if (strcmp(nargs[0], "bench") == 0) {
11fdf7f2
TL
3262 if (!pool_name || nargs.size() < 3) {
3263 usage(cerr);
3264 return 1;
3265 }
7c673cae
FG
3266 char* endptr = NULL;
3267 int seconds = strtol(nargs[1], &endptr, 10);
3268 if (*endptr) {
3269 cerr << "Invalid value for seconds: '" << nargs[1] << "'" << std::endl;
11fdf7f2 3270 return 1;
7c673cae
FG
3271 }
3272 int operation = 0;
3273 if (strcmp(nargs[2], "write") == 0)
3274 operation = OP_WRITE;
3275 else if (strcmp(nargs[2], "seq") == 0)
3276 operation = OP_SEQ_READ;
3277 else if (strcmp(nargs[2], "rand") == 0)
3278 operation = OP_RAND_READ;
11fdf7f2
TL
3279 else {
3280 usage(cerr);
3281 return 1;
3282 }
7c673cae
FG
3283 if (operation != OP_WRITE) {
3284 if (block_size_specified) {
224ce89b 3285 cerr << "-b|--block_size option can be used only with 'write' bench test"
7c673cae 3286 << std::endl;
11fdf7f2 3287 return 1;
7c673cae
FG
3288 }
3289 if (bench_write_dest != 0) {
3290 cerr << "--write-object, --write-omap and --write-xattr options can "
3291 "only be used with the 'write' bench test"
3292 << std::endl;
11fdf7f2 3293 return 1;
7c673cae
FG
3294 }
3295 }
3296 else if (bench_write_dest == 0) {
3297 bench_write_dest = OP_WRITE_DEST_OBJ;
3298 }
3299
3300 if (!formatter && output) {
224ce89b 3301 cerr << "-o|--output option can only be used with '--format' option"
7c673cae 3302 << std::endl;
11fdf7f2 3303 return 1;
7c673cae
FG
3304 }
3305 RadosBencher bencher(g_ceph_context, rados, io_ctx);
3306 bencher.set_show_time(show_time);
3307 bencher.set_write_destination(static_cast<OpWriteDest>(bench_write_dest));
3308
3309 ostream *outstream = NULL;
3310 if (formatter) {
11fdf7f2 3311 bencher.set_formatter(formatter.get());
7c673cae
FG
3312 if (output)
3313 outstream = new ofstream(output);
3314 else
3315 outstream = &cout;
3316 bencher.set_outstream(*outstream);
3317 }
3318 if (!object_size)
3319 object_size = op_size;
3320 else if (object_size < op_size)
3321 op_size = object_size;
3322 cout << "hints = " << (int)hints << std::endl;
3323 ret = bencher.aio_bench(operation, seconds,
3324 concurrent_ios, op_size, object_size,
11fdf7f2 3325 max_objects, cleanup, hints, run_name, reuse_bench, no_verify);
7c673cae 3326 if (ret != 0)
224ce89b 3327 cerr << "error during benchmark: " << cpp_strerror(ret) << std::endl;
7c673cae
FG
3328 if (formatter && output)
3329 delete outstream;
3330 }
3331 else if (strcmp(nargs[0], "cleanup") == 0) {
11fdf7f2
TL
3332 if (!pool_name) {
3333 usage(cerr);
3334 return 1;
3335 }
7c673cae
FG
3336 if (wildcard)
3337 io_ctx.set_namespace(all_nspaces);
3338 RadosBencher bencher(g_ceph_context, rados, io_ctx);
3339 ret = bencher.clean_up(prefix, concurrent_ios, run_name);
3340 if (ret != 0)
224ce89b 3341 cerr << "error during cleanup: " << cpp_strerror(ret) << std::endl;
7c673cae
FG
3342 }
3343 else if (strcmp(nargs[0], "watch") == 0) {
11fdf7f2
TL
3344 if (!pool_name || nargs.size() < 2) {
3345 usage(cerr);
3346 return 1;
3347 }
7c673cae
FG
3348 string oid(nargs[1]);
3349 RadosWatchCtx ctx(io_ctx, oid.c_str());
3350 uint64_t cookie;
3351 ret = io_ctx.watch2(oid, &cookie, &ctx);
3352 if (ret != 0)
224ce89b 3353 cerr << "error calling watch: " << cpp_strerror(ret) << std::endl;
7c673cae
FG
3354 else {
3355 cout << "press enter to exit..." << std::endl;
3356 getchar();
3357 io_ctx.unwatch2(cookie);
3358 rados.watch_flush();
3359 }
3360 }
3361 else if (strcmp(nargs[0], "notify") == 0) {
11fdf7f2
TL
3362 if (!pool_name || nargs.size() < 3) {
3363 usage(cerr);
3364 return 1;
3365 }
7c673cae
FG
3366 string oid(nargs[1]);
3367 string msg(nargs[2]);
3368 bufferlist bl, replybl;
11fdf7f2 3369 encode(msg, bl);
7c673cae
FG
3370 ret = io_ctx.notify2(oid, bl, 10000, &replybl);
3371 if (ret != 0)
224ce89b 3372 cerr << "error calling notify: " << cpp_strerror(ret) << std::endl;
7c673cae
FG
3373 if (replybl.length()) {
3374 map<pair<uint64_t,uint64_t>,bufferlist> rm;
3375 set<pair<uint64_t,uint64_t> > missed;
11fdf7f2
TL
3376 auto p = replybl.cbegin();
3377 decode(rm, p);
3378 decode(missed, p);
7c673cae
FG
3379 for (map<pair<uint64_t,uint64_t>,bufferlist>::iterator p = rm.begin();
3380 p != rm.end();
3381 ++p) {
3382 cout << "reply client." << p->first.first
3383 << " cookie " << p->first.second
3384 << " : " << p->second.length() << " bytes" << std::endl;
3385 if (p->second.length())
3386 p->second.hexdump(cout);
3387 }
3388 for (multiset<pair<uint64_t,uint64_t> >::iterator p = missed.begin();
3389 p != missed.end(); ++p) {
3390 cout << "timeout client." << p->first
3391 << " cookie " << p->second << std::endl;
3392 }
3393 }
3394 } else if (strcmp(nargs[0], "set-alloc-hint") == 0) {
f67539c2
TL
3395 // cmd, [oid, ] obj_size, write_size
3396 if (!pool_name || nargs.size() < (obj_name ? 3 : 4)) {
11fdf7f2
TL
3397 usage(cerr);
3398 return 1;
3399 }
7c673cae 3400 string err;
f67539c2 3401 uint64_t expected_object_size = strict_strtoll(nargs[obj_name ? 1 : 2], 10, &err);
7c673cae
FG
3402 if (!err.empty()) {
3403 cerr << "couldn't parse expected_object_size: " << err << std::endl;
11fdf7f2
TL
3404 usage(cerr);
3405 return 1;
7c673cae 3406 }
f67539c2 3407 uint64_t expected_write_size = strict_strtoll(nargs[obj_name ? 2 : 3], 10, &err);
7c673cae
FG
3408 if (!err.empty()) {
3409 cerr << "couldn't parse expected_write_size: " << err << std::endl;
11fdf7f2
TL
3410 usage(cerr);
3411 return 1;
7c673cae 3412 }
f67539c2
TL
3413 if (!obj_name) {
3414 obj_name = nargs[1];
3415 }
3416 ret = io_ctx.set_alloc_hint(*obj_name, expected_object_size, expected_write_size);
7c673cae 3417 if (ret < 0) {
f67539c2 3418 cerr << "error setting alloc-hint " << pool_name << "/" << prettify(*obj_name) << ": "
7c673cae 3419 << cpp_strerror(ret) << std::endl;
11fdf7f2 3420 return 1;
7c673cae
FG
3421 }
3422 } else if (strcmp(nargs[0], "load-gen") == 0) {
3423 if (!pool_name) {
3424 cerr << "error: must specify pool" << std::endl;
11fdf7f2
TL
3425 usage(cerr);
3426 return 1;
7c673cae
FG
3427 }
3428 LoadGen lg(&rados);
3429 if (min_obj_len)
3430 lg.min_obj_len = min_obj_len;
3431 if (max_obj_len)
3432 lg.max_obj_len = max_obj_len;
3433 if (min_op_len)
3434 lg.min_op_len = min_op_len;
3435 if (max_op_len)
3436 lg.max_op_len = max_op_len;
3437 if (max_ops)
3438 lg.max_ops = max_ops;
3439 if (max_backlog)
3440 lg.max_backlog = max_backlog;
3441 if (target_throughput)
11fdf7f2 3442 lg.target_throughput = target_throughput;
7c673cae
FG
3443 if (read_percent >= 0)
3444 lg.read_percent = read_percent;
3445 if (num_objs)
3446 lg.num_objs = num_objs;
3447 if (run_length)
3448 lg.run_length = run_length;
11fdf7f2
TL
3449 if (offset_align)
3450 lg.offset_align = offset_align;
7c673cae
FG
3451
3452 cout << "run length " << run_length << " seconds" << std::endl;
3453 cout << "preparing " << lg.num_objs << " objects" << std::endl;
3454 ret = lg.bootstrap(pool_name);
3455 if (ret < 0) {
3456 cerr << "load-gen bootstrap failed" << std::endl;
11fdf7f2 3457 return 1;
7c673cae
FG
3458 }
3459 cout << "load-gen will run " << lg.run_length << " seconds" << std::endl;
3460 lg.run();
3461 lg.cleanup();
3462 } else if (strcmp(nargs[0], "listomapkeys") == 0) {
f67539c2 3463 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3464 usage(cerr);
3465 return 1;
3466 }
f67539c2
TL
3467 if (!obj_name) {
3468 obj_name = nargs[1];
3469 }
9f95a23c
TL
3470 string last_read;
3471 bool more = true;
3472 do {
3473 set<string> out_keys;
f67539c2 3474 ret = io_ctx.omap_get_keys2(*obj_name, last_read, MAX_OMAP_BYTES_PER_REQUEST, &out_keys, &more);
9f95a23c
TL
3475 if (ret < 0) {
3476 cerr << "error getting omap key set " << pool_name << "/"
f67539c2 3477 << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
9f95a23c
TL
3478 return 1;
3479 }
7c673cae 3480
9f95a23c
TL
3481 for (auto &key : out_keys) {
3482 cout << key << std::endl;
3483 last_read = std::move(key);
3484 }
3485 } while (more);
7c673cae 3486 } else if (strcmp(nargs[0], "lock") == 0) {
11fdf7f2
TL
3487 if (!pool_name) {
3488 usage(cerr);
3489 return 1;
3490 }
7c673cae
FG
3491
3492 if (!formatter) {
11fdf7f2 3493 formatter = std::make_unique<JSONFormatter>(pretty_format);
7c673cae 3494 }
11fdf7f2 3495 ret = do_lock_cmd(nargs, opts, &io_ctx, formatter.get());
7c673cae 3496 } else if (strcmp(nargs[0], "listwatchers") == 0) {
11fdf7f2
TL
3497 if (!pool_name || nargs.size() < 2) {
3498 usage(cerr);
3499 return 1;
3500 }
7c673cae
FG
3501
3502 string oid(nargs[1]);
3503 std::list<obj_watch_t> lw;
3504
3505 ret = io_ctx.list_watchers(oid, &lw);
3506 if (ret < 0) {
3507 cerr << "error listing watchers " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 3508 return 1;
7c673cae
FG
3509 }
3510 else
3511 ret = 0;
3512
3513 for (std::list<obj_watch_t>::iterator i = lw.begin(); i != lw.end(); ++i) {
3514 cout << "watcher=" << i->addr << " client." << i->watcher_id << " cookie=" << i->cookie << std::endl;
3515 }
3516 } else if (strcmp(nargs[0], "listsnaps") == 0) {
f67539c2 3517 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3518 usage(cerr);
3519 return 1;
3520 }
f67539c2
TL
3521 if (!obj_name) {
3522 obj_name = nargs[1];
3523 }
7c673cae 3524
7c673cae 3525 snap_set_t ls;
7c673cae 3526 io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
f67539c2 3527 ret = io_ctx.list_snaps(*obj_name, &ls);
7c673cae 3528 if (ret < 0) {
f67539c2 3529 cerr << "error listing snap shots " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2 3530 return 1;
7c673cae
FG
3531 }
3532 else
3533 ret = 0;
3534
3535 map<snap_t,string> snamemap;
3536 if (formatter || pretty_format) {
3537 vector<snap_t> snaps;
3538 io_ctx.snap_list(&snaps);
3539 for (vector<snap_t>::iterator i = snaps.begin();
3540 i != snaps.end(); ++i) {
3541 string s;
3542 if (io_ctx.snap_get_name(*i, &s) < 0)
3543 continue;
3544 snamemap.insert(pair<snap_t,string>(*i, s));
3545 }
3546 }
3547
3548 if (formatter) {
3549 formatter->open_object_section("object");
f67539c2 3550 formatter->dump_string("name", *obj_name);
7c673cae
FG
3551 formatter->open_array_section("clones");
3552 } else {
f67539c2 3553 cout << prettify(*obj_name) << ":" << std::endl;
7c673cae
FG
3554 cout << "cloneid snaps size overlap" << std::endl;
3555 }
3556
3557 for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
3558 ci != ls.clones.end(); ++ci) {
3559
3560 if (formatter) formatter->open_object_section("clone");
3561
3562 if (ci->cloneid == librados::SNAP_HEAD) {
3563 if (formatter)
3564 formatter->dump_string("id", "head");
3565 else
3566 cout << "head";
3567 } else {
3568 if (formatter)
3569 formatter->dump_unsigned("id", ci->cloneid);
3570 else
3571 cout << ci->cloneid;
3572 }
3573
3574 if (formatter)
3575 formatter->open_array_section("snapshots");
3576 else
3577 cout << "\t";
3578
3579 if (!formatter && ci->snaps.empty()) {
3580 cout << "-";
3581 }
3582 for (std::vector<snap_t>::const_iterator snapindex = ci->snaps.begin();
3583 snapindex != ci->snaps.end(); ++snapindex) {
3584
3585 map<snap_t,string>::iterator si;
3586
3587 if (formatter || pretty_format) si = snamemap.find(*snapindex);
3588
3589 if (formatter) {
3590 formatter->open_object_section("snapshot");
3591 formatter->dump_unsigned("id", *snapindex);
3592 if (si != snamemap.end())
3593 formatter->dump_string("name", si->second);
3594 formatter->close_section(); //snapshot
3595 } else {
3596 if (snapindex != ci->snaps.begin()) cout << ",";
3597 if (!pretty_format || (si == snamemap.end()))
3598 cout << *snapindex;
3599 else
3600 cout << si->second << "(" << *snapindex << ")";
3601 }
3602 }
3603
3604 if (formatter) {
3605 formatter->close_section(); //Snapshots
3606 formatter->dump_unsigned("size", ci->size);
3607 } else {
3608 cout << "\t" << ci->size;
3609 }
3610
3611 if (ci->cloneid != librados::SNAP_HEAD) {
3612 if (formatter)
3613 formatter->open_array_section("overlaps");
3614 else
3615 cout << "\t[";
3616
3617 for (std::vector< std::pair<uint64_t,uint64_t> >::iterator ovi = ci->overlap.begin();
3618 ovi != ci->overlap.end(); ++ovi) {
3619 if (formatter) {
3620 formatter->open_object_section("section");
3621 formatter->dump_unsigned("start", ovi->first);
3622 formatter->dump_unsigned("length", ovi->second);
3623 formatter->close_section(); //section
3624 } else {
3625 if (ovi != ci->overlap.begin()) cout << ",";
3626 cout << ovi->first << "~" << ovi->second;
3627 }
3628 }
3629 if (formatter)
3630 formatter->close_section(); //overlaps
3631 else
3632 cout << "]" << std::endl;
3633 }
3634 if (formatter) formatter->close_section(); //clone
3635 }
3636 if (formatter) {
3637 formatter->close_section(); //clones
3638 formatter->close_section(); //object
3639 formatter->flush(cout);
3640 } else {
3641 cout << std::endl;
3642 }
3643 } else if (strcmp(nargs[0], "list-inconsistent-pg") == 0) {
3644 if (!formatter) {
11fdf7f2 3645 formatter = std::make_unique<JSONFormatter>(pretty_format);
7c673cae
FG
3646 }
3647 ret = do_get_inconsistent_pg_cmd(nargs, rados, *formatter);
3648 } else if (strcmp(nargs[0], "list-inconsistent-obj") == 0) {
3649 if (!formatter) {
11fdf7f2 3650 formatter = std::make_unique<JSONFormatter>(pretty_format);
7c673cae
FG
3651 }
3652 ret = do_get_inconsistent_cmd<inconsistent_obj_t>(nargs, rados, *formatter);
3653 } else if (strcmp(nargs[0], "list-inconsistent-snapset") == 0) {
3654 if (!formatter) {
11fdf7f2 3655 formatter = std::make_unique<JSONFormatter>(pretty_format);
7c673cae
FG
3656 }
3657 ret = do_get_inconsistent_cmd<inconsistent_snapset_t>(nargs, rados, *formatter);
3658 } else if (strcmp(nargs[0], "cache-flush") == 0) {
f67539c2 3659 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3660 usage(cerr);
3661 return 1;
3662 }
f67539c2
TL
3663 if (!obj_name) {
3664 obj_name = nargs[1];
3665 }
7c673cae
FG
3666 if (with_clones) {
3667 snap_set_t ls;
3668 io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
f67539c2 3669 ret = io_ctx.list_snaps(*obj_name, &ls);
7c673cae 3670 if (ret < 0) {
f67539c2 3671 cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": "
7c673cae 3672 << cpp_strerror(ret) << std::endl;
11fdf7f2 3673 return 1;
7c673cae
FG
3674 }
3675 for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
3676 ci != ls.clones.end(); ++ci) {
3677 if (snapid != CEPH_NOSNAP && ci->cloneid > snapid)
3678 break;
3679 io_ctx.snap_set_read(ci->cloneid);
f67539c2 3680 ret = do_cache_flush(io_ctx, *obj_name);
7c673cae 3681 if (ret < 0) {
f67539c2 3682 cerr << "error from cache-flush " << prettify(*obj_name) << ": "
7c673cae 3683 << cpp_strerror(ret) << std::endl;
11fdf7f2 3684 return 1;
7c673cae
FG
3685 }
3686 }
3687 } else {
f67539c2 3688 ret = do_cache_flush(io_ctx, *obj_name);
7c673cae 3689 if (ret < 0) {
f67539c2 3690 cerr << "error from cache-flush " << prettify(*obj_name) << ": "
7c673cae 3691 << cpp_strerror(ret) << std::endl;
11fdf7f2 3692 return 1;
7c673cae
FG
3693 }
3694 }
3695 } else if (strcmp(nargs[0], "cache-try-flush") == 0) {
f67539c2 3696 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3697 usage(cerr);
3698 return 1;
3699 }
f67539c2
TL
3700 if (!obj_name) {
3701 obj_name = nargs[1];
3702 }
7c673cae
FG
3703 if (with_clones) {
3704 snap_set_t ls;
3705 io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
f67539c2 3706 ret = io_ctx.list_snaps(*obj_name, &ls);
7c673cae 3707 if (ret < 0) {
f67539c2 3708 cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": "
7c673cae 3709 << cpp_strerror(ret) << std::endl;
11fdf7f2 3710 return 1;
7c673cae
FG
3711 }
3712 for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
3713 ci != ls.clones.end(); ++ci) {
3714 if (snapid != CEPH_NOSNAP && ci->cloneid > snapid)
3715 break;
3716 io_ctx.snap_set_read(ci->cloneid);
f67539c2 3717 ret = do_cache_try_flush(io_ctx, *obj_name);
7c673cae 3718 if (ret < 0) {
f67539c2 3719 cerr << "error from cache-flush " << prettify(*obj_name) << ": "
7c673cae 3720 << cpp_strerror(ret) << std::endl;
11fdf7f2 3721 return 1;
7c673cae
FG
3722 }
3723 }
3724 } else {
f67539c2 3725 ret = do_cache_try_flush(io_ctx, *obj_name);
7c673cae 3726 if (ret < 0) {
f67539c2 3727 cerr << "error from cache-flush " << prettify(*obj_name) << ": "
7c673cae 3728 << cpp_strerror(ret) << std::endl;
11fdf7f2 3729 return 1;
7c673cae
FG
3730 }
3731 }
3732 } else if (strcmp(nargs[0], "cache-evict") == 0) {
f67539c2 3733 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3734 usage(cerr);
3735 return 1;
3736 }
f67539c2
TL
3737 if (!obj_name) {
3738 obj_name = nargs[1];
3739 }
7c673cae
FG
3740 if (with_clones) {
3741 snap_set_t ls;
3742 io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
f67539c2 3743 ret = io_ctx.list_snaps(*obj_name, &ls);
7c673cae 3744 if (ret < 0) {
f67539c2 3745 cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": "
7c673cae 3746 << cpp_strerror(ret) << std::endl;
11fdf7f2 3747 return 1;
7c673cae
FG
3748 }
3749 for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
3750 ci != ls.clones.end(); ++ci) {
3751 if (snapid != CEPH_NOSNAP && ci->cloneid > snapid)
3752 break;
3753 io_ctx.snap_set_read(ci->cloneid);
f67539c2 3754 ret = do_cache_evict(io_ctx, *obj_name);
7c673cae 3755 if (ret < 0) {
f67539c2 3756 cerr << "error from cache-flush " << prettify(*obj_name) << ": "
7c673cae 3757 << cpp_strerror(ret) << std::endl;
11fdf7f2 3758 return 1;
7c673cae
FG
3759 }
3760 }
3761 } else {
f67539c2 3762 ret = do_cache_evict(io_ctx, *obj_name);
7c673cae 3763 if (ret < 0) {
f67539c2 3764 cerr << "error from cache-flush " << prettify(*obj_name) << ": "
7c673cae 3765 << cpp_strerror(ret) << std::endl;
11fdf7f2 3766 return 1;
7c673cae
FG
3767 }
3768 }
3769 } else if (strcmp(nargs[0], "cache-flush-evict-all") == 0) {
11fdf7f2
TL
3770 if (!pool_name) {
3771 usage(cerr);
3772 return 1;
3773 }
7c673cae
FG
3774 ret = do_cache_flush_evict_all(io_ctx, true);
3775 if (ret < 0) {
11fdf7f2
TL
3776 cerr << "cache-flush-evict-all finished with errors" << std::endl;
3777 return 1;
7c673cae
FG
3778 }
3779 } else if (strcmp(nargs[0], "cache-try-flush-evict-all") == 0) {
11fdf7f2
TL
3780 if (!pool_name) {
3781 usage(cerr);
3782 return 1;
3783 }
7c673cae
FG
3784 ret = do_cache_flush_evict_all(io_ctx, false);
3785 if (ret < 0) {
11fdf7f2
TL
3786 cerr << "cache-try-flush-evict-all finished with errors" << std::endl;
3787 return 1;
7c673cae 3788 }
31f18b77 3789 } else if (strcmp(nargs[0], "set-redirect") == 0) {
11fdf7f2
TL
3790 if (!pool_name) {
3791 usage(cerr);
3792 return 1;
3793 }
31f18b77
FG
3794
3795 const char *target = target_pool_name;
3796 if (!target)
3797 target = pool_name;
3798
3799 const char *target_obj;
3800 if (nargs.size() < 3) {
3801 if (strcmp(target, pool_name) == 0) {
3802 cerr << "cannot copy object into itself" << std::endl;
11fdf7f2 3803 return 1;
31f18b77
FG
3804 }
3805 target_obj = nargs[1];
3806 } else {
3807 target_obj = nargs[2];
3808 }
3809
3810 IoCtx target_ctx;
3811 ret = rados.ioctx_create(target, target_ctx);
3812 if (target_oloc.size()) {
3813 target_ctx.locator_set_key(target_oloc);
3814 }
3815 if (target_nspace.size()) {
3816 target_ctx.set_namespace(target_nspace);
3817 }
3818
3819 ObjectWriteOperation op;
11fdf7f2
TL
3820 if (with_reference) {
3821 op.set_redirect(target_obj, target_ctx, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
3822 } else {
3823 op.set_redirect(target_obj, target_ctx, 0);
3824 }
31f18b77
FG
3825 ret = io_ctx.operate(nargs[1], &op);
3826 if (ret < 0) {
3827 cerr << "error set-redirect " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl;
11fdf7f2
TL
3828 return 1;
3829 }
3830 } else if (strcmp(nargs[0], "set-chunk") == 0) {
3831 if (!pool_name) {
3832 usage(cerr);
3833 return 1;
3834 }
3835
3836 const char *target = target_pool_name;
3837 if (!target)
3838 target = pool_name;
3839
3840 uint64_t offset;
3841 uint64_t length;
3842 uint64_t tgt_offset;
3843 string tgt_oid;
3844 if (nargs.size() < 6) {
3845 usage(cerr);
3846 return 1;
3847 } else {
3848 char* endptr = NULL;
3849 offset = strtoull(nargs[2], &endptr, 10);
3850 if (*endptr) {
3851 cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
3852 return 1;
3853 }
3854 length = strtoull(nargs[3], &endptr, 10);
3855 if (*endptr) {
3856 cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
3857 return 1;
3858 }
3859 tgt_oid = string(nargs[4]);
3860 tgt_offset = strtoull(nargs[5], &endptr, 10);
3861 if (*endptr) {
3862 cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
3863 return 1;
3864 }
3865 }
3866
3867 IoCtx target_ctx;
3868 ret = rados.ioctx_create(target, target_ctx);
f67539c2
TL
3869 ObjectReadOperation op;
3870 op.set_chunk(offset, length, target_ctx, tgt_oid, tgt_offset, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
3871 ret = io_ctx.operate(nargs[1], &op, NULL);
11fdf7f2
TL
3872 if (ret < 0) {
3873 cerr << "error set-chunk " << pool_name << "/" << nargs[1] << " " << " offset " << offset
3874 << " length " << length << " target_pool " << target
3875 << "tgt_offset: " << tgt_offset << " : " << cpp_strerror(ret) << std::endl;
3876 return 1;
3877 }
3878 } else if (strcmp(nargs[0], "tier-promote") == 0) {
f67539c2 3879 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3880 usage(cerr);
3881 return 1;
3882 }
f67539c2
TL
3883 if (!obj_name) {
3884 obj_name = nargs[1];
3885 }
11fdf7f2
TL
3886 ObjectWriteOperation op;
3887 op.tier_promote();
f67539c2 3888 ret = io_ctx.operate(*obj_name, &op);
11fdf7f2 3889 if (ret < 0) {
f67539c2 3890 cerr << "error tier-promote " << pool_name << "/" << prettify(*obj_name) << " : "
11fdf7f2
TL
3891 << cpp_strerror(ret) << std::endl;
3892 return 1;
3893 }
3894 } else if (strcmp(nargs[0], "unset-manifest") == 0) {
f67539c2 3895 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
11fdf7f2
TL
3896 usage(cerr);
3897 return 1;
3898 }
f67539c2
TL
3899 if (!obj_name) {
3900 obj_name = nargs[1];
3901 }
11fdf7f2
TL
3902 ObjectWriteOperation op;
3903 op.unset_manifest();
f67539c2 3904 ret = io_ctx.operate(*obj_name, &op);
11fdf7f2 3905 if (ret < 0) {
f67539c2 3906 cerr << "error unset-manifest " << pool_name << "/" << prettify(*obj_name) << " : "
11fdf7f2
TL
3907 << cpp_strerror(ret) << std::endl;
3908 return 1;
31f18b77 3909 }
9f95a23c 3910 } else if (strcmp(nargs[0], "tier-flush") == 0) {
f67539c2 3911 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
9f95a23c
TL
3912 usage(cerr);
3913 return 1;
3914 }
f67539c2
TL
3915 if (!obj_name) {
3916 obj_name = nargs[1];
3917 }
3918 ObjectReadOperation op;
9f95a23c 3919 op.tier_flush();
f67539c2
TL
3920 librados::AioCompletion *completion =
3921 librados::Rados::aio_create_completion();
3922 io_ctx.aio_operate(*obj_name, completion, &op,
3923 librados::OPERATION_IGNORE_CACHE |
3924 librados::OPERATION_IGNORE_OVERLAY,
3925 NULL);
3926 completion->wait_for_complete();
3927 ret = completion->get_return_value();
3928 completion->release();
3929 if (ret < 0) {
3930 cerr << "error tier-flush " << pool_name << "/" << prettify(*obj_name) << " : "
3931 << cpp_strerror(ret) << std::endl;
3932 return 1;
3933 }
3934 } else if (strcmp(nargs[0], "tier-evict") == 0) {
3935 if (!pool_name || (nargs.size() < 2 && !obj_name)) {
3936 usage(cerr);
3937 return 1;
3938 }
3939 if (!obj_name) {
3940 obj_name = nargs[1];
3941 }
3942 ObjectReadOperation op;
3943 op.tier_evict();
3944 librados::AioCompletion *completion =
3945 librados::Rados::aio_create_completion();
3946 io_ctx.aio_operate(*obj_name, completion, &op,
3947 librados::OPERATION_IGNORE_CACHE |
3948 librados::OPERATION_IGNORE_OVERLAY,
3949 NULL);
3950 completion->wait_for_complete();
3951 ret = completion->get_return_value();
3952 completion->release();
9f95a23c 3953 if (ret < 0) {
f67539c2 3954 cerr << "error tier-evict " << pool_name << "/" << prettify(*obj_name) << " : "
9f95a23c
TL
3955 << cpp_strerror(ret) << std::endl;
3956 return 1;
3957 }
7c673cae
FG
3958 } else if (strcmp(nargs[0], "export") == 0) {
3959 // export [filename]
3960 if (!pool_name || nargs.size() > 2) {
11fdf7f2
TL
3961 usage(cerr);
3962 return 1;
7c673cae
FG
3963 }
3964
3965 int file_fd;
3966 if (nargs.size() < 2 || std::string(nargs[1]) == "-") {
3967 file_fd = STDOUT_FILENO;
3968 } else {
f67539c2 3969 file_fd = open(nargs[1], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
7c673cae
FG
3970 if (file_fd < 0) {
3971 cerr << "Error opening '" << nargs[1] << "': "
3972 << cpp_strerror(file_fd) << std::endl;
11fdf7f2 3973 return 1;
7c673cae
FG
3974 }
3975 }
3976
3977 ret = PoolDump(file_fd).dump(&io_ctx);
3978
3979 if (file_fd != STDIN_FILENO) {
3980 VOID_TEMP_FAILURE_RETRY(::close(file_fd));
3981 }
3982
3983 if (ret < 0) {
3984 cerr << "error from export: "
3985 << cpp_strerror(ret) << std::endl;
11fdf7f2 3986 return 1;
7c673cae
FG
3987 }
3988 } else if (strcmp(nargs[0], "import") == 0) {
3989 // import [--no-overwrite] [--dry-run] <filename | - >
3990 if (!pool_name || nargs.size() > 4 || nargs.size() < 2) {
11fdf7f2
TL
3991 usage(cerr);
3992 return 1;
7c673cae
FG
3993 }
3994
3995 // Last arg is the filename
3996 std::string const filename = nargs[nargs.size() - 1];
3997
3998 // All other args may be flags
3999 bool dry_run = false;
4000 bool no_overwrite = false;
4001 for (unsigned i = 1; i < nargs.size() - 1; ++i) {
4002 std::string arg(nargs[i]);
4003
4004 if (arg == std::string("--no-overwrite")) {
4005 no_overwrite = true;
4006 } else if (arg == std::string("--dry-run")) {
4007 dry_run = true;
4008 } else {
4009 std::cerr << "Invalid argument '" << arg << "'" << std::endl;
11fdf7f2 4010 return 1;
7c673cae
FG
4011 }
4012 }
4013
4014 int file_fd;
4015 if (filename == "-") {
4016 file_fd = STDIN_FILENO;
4017 } else {
f67539c2 4018 file_fd = open(filename.c_str(), O_RDONLY|O_BINARY);
7c673cae
FG
4019 if (file_fd < 0) {
4020 cerr << "Error opening '" << filename << "': "
4021 << cpp_strerror(file_fd) << std::endl;
11fdf7f2 4022 return 1;
7c673cae
FG
4023 }
4024 }
4025
4026 ret = RadosImport(file_fd, 0, dry_run).import(io_ctx, no_overwrite);
4027
4028 if (file_fd != STDIN_FILENO) {
4029 VOID_TEMP_FAILURE_RETRY(::close(file_fd));
4030 }
4031
4032 if (ret < 0) {
4033 cerr << "error from import: "
4034 << cpp_strerror(ret) << std::endl;
11fdf7f2 4035 return 1;
7c673cae
FG
4036 }
4037 } else {
4038 cerr << "unrecognized command " << nargs[0] << "; -h or --help for usage" << std::endl;
4039 ret = -EINVAL;
7c673cae
FG
4040 }
4041
4042 if (ret < 0)
4043 cerr << "error " << (-ret) << ": " << cpp_strerror(ret) << std::endl;
4044
7c673cae
FG
4045 return (ret < 0) ? 1 : 0;
4046}
4047
4048int main(int argc, const char **argv)
4049{
20effc67 4050 auto args = argv_to_vec(argc, argv);
11fdf7f2
TL
4051 if (args.empty()) {
4052 cerr << argv[0] << ": -h or --help for usage" << std::endl;
4053 exit(1);
4054 }
4055 if (ceph_argparse_need_usage(args)) {
4056 usage(cout);
4057 exit(0);
4058 }
7c673cae
FG
4059
4060 std::map < std::string, std::string > opts;
4061 std::string val;
4062
4063 // Necessary to support usage of -f for formatting,
4064 // since global_init will remove the -f using ceph
4065 // argparse procedures.
4066 for (auto j = args.begin(); j != args.end(); ++j) {
4067 if (strcmp(*j, "--") == 0) {
4068 break;
4069 } else if ((j+1) == args.end()) {
4070 // This can't be a formatting call (no format arg)
4071 break;
4072 } else if (strcmp(*j, "-f") == 0) {
4073 val = *(j+1);
4074 unique_ptr<Formatter> formatter(Formatter::create(val.c_str()));
4075
4076 if (formatter) {
4077 j = args.erase(j);
4078 opts["format"] = val;
4079
4080 j = args.erase(j);
4081 break;
4082 }
4083 }
4084 }
4085
4086 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
4087 CODE_ENVIRONMENT_UTILITY, 0);
4088 common_init_finish(g_ceph_context);
4089
4090 std::vector<const char*>::iterator i;
4091 for (i = args.begin(); i != args.end(); ) {
4092 if (ceph_argparse_double_dash(args, i)) {
4093 break;
7c673cae
FG
4094 } else if (ceph_argparse_flag(args, i, "--force-full", (char*)NULL)) {
4095 opts["force-full"] = "true";
4096 } else if (ceph_argparse_flag(args, i, "-d", "--delete-after", (char*)NULL)) {
4097 opts["delete-after"] = "true";
4098 } else if (ceph_argparse_flag(args, i, "-C", "--create", "--create-pool",
4099 (char*)NULL)) {
4100 opts["create"] = "true";
4101 } else if (ceph_argparse_flag(args, i, "--pretty-format", (char*)NULL)) {
4102 opts["pretty-format"] = "true";
4103 } else if (ceph_argparse_flag(args, i, "--show-time", (char*)NULL)) {
4104 opts["show-time"] = "true";
4105 } else if (ceph_argparse_flag(args, i, "--no-cleanup", (char*)NULL)) {
4106 opts["no-cleanup"] = "true";
4107 } else if (ceph_argparse_flag(args, i, "--no-hints", (char*)NULL)) {
4108 opts["no-hints"] = "true";
11fdf7f2
TL
4109 } else if (ceph_argparse_flag(args, i, "--reuse-bench", (char*)NULL)) {
4110 opts["reuse-bench"] = "true";
7c673cae
FG
4111 } else if (ceph_argparse_flag(args, i, "--no-verify", (char*)NULL)) {
4112 opts["no-verify"] = "true";
4113 } else if (ceph_argparse_witharg(args, i, &val, "--run-name", (char*)NULL)) {
4114 opts["run-name"] = val;
4115 } else if (ceph_argparse_witharg(args, i, &val, "--prefix", (char*)NULL)) {
4116 opts["prefix"] = val;
4117 } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) {
4118 opts["pool"] = val;
4119 } else if (ceph_argparse_witharg(args, i, &val, "--target-pool", (char*)NULL)) {
4120 opts["target_pool"] = val;
4121 } else if (ceph_argparse_witharg(args, i, &val, "--object-locator" , (char *)NULL)) {
4122 opts["object_locator"] = val;
4123 } else if (ceph_argparse_witharg(args, i, &val, "--target-locator" , (char *)NULL)) {
4124 opts["target_locator"] = val;
4125 } else if (ceph_argparse_witharg(args, i, &val, "--target-nspace" , (char *)NULL)) {
4126 opts["target_nspace"] = val;
11fdf7f2 4127#ifdef WITH_LIBRADOSSTRIPER
7c673cae
FG
4128 } else if (ceph_argparse_flag(args, i, "--striper" , (char *)NULL)) {
4129 opts["striper"] = "true";
11fdf7f2 4130#endif
7c673cae
FG
4131 } else if (ceph_argparse_witharg(args, i, &val, "-t", "--concurrent-ios", (char*)NULL)) {
4132 opts["concurrent-ios"] = val;
4133 } else if (ceph_argparse_witharg(args, i, &val, "--block-size", (char*)NULL)) {
4134 opts["block-size"] = val;
4135 } else if (ceph_argparse_witharg(args, i, &val, "-b", (char*)NULL)) {
4136 opts["block-size"] = val;
4137 } else if (ceph_argparse_witharg(args, i, &val, "--object-size", (char*)NULL)) {
4138 opts["object-size"] = val;
4139 } else if (ceph_argparse_witharg(args, i, &val, "--max-objects", (char*)NULL)) {
4140 opts["max-objects"] = val;
4141 } else if (ceph_argparse_witharg(args, i, &val, "--offset", (char*)NULL)) {
4142 opts["offset"] = val;
9f95a23c 4143 } else if (ceph_argparse_witharg(args, i, &val, "-O", (char*)NULL)) {
7c673cae
FG
4144 opts["object-size"] = val;
4145 } else if (ceph_argparse_witharg(args, i, &val, "-s", "--snap", (char*)NULL)) {
4146 opts["snap"] = val;
4147 } else if (ceph_argparse_witharg(args, i, &val, "-S", "--snapid", (char*)NULL)) {
4148 opts["snapid"] = val;
4149 } else if (ceph_argparse_witharg(args, i, &val, "--min-object-size", (char*)NULL)) {
4150 opts["min-object-size"] = val;
4151 } else if (ceph_argparse_witharg(args, i, &val, "--max-object-size", (char*)NULL)) {
4152 opts["max-object-size"] = val;
4153 } else if (ceph_argparse_witharg(args, i, &val, "--min-op-len", (char*)NULL)) {
4154 opts["min-op-len"] = val;
4155 } else if (ceph_argparse_witharg(args, i, &val, "--max-op-len", (char*)NULL)) {
4156 opts["max-op-len"] = val;
4157 } else if (ceph_argparse_witharg(args, i, &val, "--max-ops", (char*)NULL)) {
4158 opts["max-ops"] = val;
4159 } else if (ceph_argparse_witharg(args, i, &val, "--max-backlog", (char*)NULL)) {
4160 opts["max-backlog"] = val;
4161 } else if (ceph_argparse_witharg(args, i, &val, "--target-throughput", (char*)NULL)) {
4162 opts["target-throughput"] = val;
11fdf7f2
TL
4163 } else if (ceph_argparse_witharg(args, i, &val, "--offset-align", (char*)NULL)) {
4164 opts["offset_align"] = val;
7c673cae
FG
4165 } else if (ceph_argparse_witharg(args, i, &val, "--read-percent", (char*)NULL)) {
4166 opts["read-percent"] = val;
4167 } else if (ceph_argparse_witharg(args, i, &val, "--num-objects", (char*)NULL)) {
4168 opts["num-objects"] = val;
4169 } else if (ceph_argparse_witharg(args, i, &val, "--run-length", (char*)NULL)) {
4170 opts["run-length"] = val;
4171 } else if (ceph_argparse_witharg(args, i, &val, "--workers", (char*)NULL)) {
4172 opts["workers"] = val;
11fdf7f2 4173 } else if (ceph_argparse_witharg(args, i, &val, "-f", "--format", (char*)NULL)) {
7c673cae
FG
4174 opts["format"] = val;
4175 } else if (ceph_argparse_witharg(args, i, &val, "--lock-tag", (char*)NULL)) {
4176 opts["lock-tag"] = val;
4177 } else if (ceph_argparse_witharg(args, i, &val, "--lock-cookie", (char*)NULL)) {
4178 opts["lock-cookie"] = val;
4179 } else if (ceph_argparse_witharg(args, i, &val, "--lock-description", (char*)NULL)) {
4180 opts["lock-description"] = val;
4181 } else if (ceph_argparse_witharg(args, i, &val, "--lock-duration", (char*)NULL)) {
4182 opts["lock-duration"] = val;
4183 } else if (ceph_argparse_witharg(args, i, &val, "--lock-type", (char*)NULL)) {
4184 opts["lock-type"] = val;
4185 } else if (ceph_argparse_witharg(args, i, &val, "-N", "--namespace", (char*)NULL)) {
4186 opts["namespace"] = val;
4187 } else if (ceph_argparse_flag(args, i, "--all", (char*)NULL)) {
4188 opts["all"] = "true";
4189 } else if (ceph_argparse_flag(args, i, "--default", (char*)NULL)) {
4190 opts["default"] = "true";
4191 } else if (ceph_argparse_witharg(args, i, &val, "-o", "--output", (char*)NULL)) {
4192 opts["output"] = val;
4193 } else if (ceph_argparse_flag(args, i, "--write-omap", (char*)NULL)) {
4194 opts["write-dest-omap"] = "true";
4195 } else if (ceph_argparse_flag(args, i, "--write-object", (char*)NULL)) {
4196 opts["write-dest-obj"] = "true";
4197 } else if (ceph_argparse_flag(args, i, "--write-xattr", (char*)NULL)) {
4198 opts["write-dest-xattr"] = "true";
4199 } else if (ceph_argparse_flag(args, i, "--with-clones", (char*)NULL)) {
4200 opts["with-clones"] = "true";
4201 } else if (ceph_argparse_witharg(args, i, &val, "--omap-key-file", (char*)NULL)) {
4202 opts["omap-key-file"] = val;
f67539c2
TL
4203 } else if (ceph_argparse_witharg(args, i, &val, "--obj-name-file", (char*)NULL)) {
4204 opts["obj-name-file"] = val;
11fdf7f2
TL
4205 } else if (ceph_argparse_flag(args, i, "--with-reference", (char*)NULL)) {
4206 opts["with-reference"] = "true";
4207 } else if (ceph_argparse_witharg(args, i, &val, "--pgid", (char*)NULL)) {
4208 opts["pgid"] = val;
f67539c2
TL
4209 } else if (ceph_argparse_witharg(args, i, &val, "--input-file", (char*)NULL)) {
4210 opts["input_file"] = val;
7c673cae
FG
4211 } else {
4212 if (val[0] == '-')
4213 usage_exit();
4214 ++i;
4215 }
4216 }
4217
4218 if (args.empty()) {
4219 cerr << "rados: you must give an action. Try --help" << std::endl;
4220 return 1;
4221 }
4222
4223 return rados_tool_common(opts, args);
4224}