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