]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/tools/rados/rados.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / tools / rados / rados.cc
index 909f0af17c4393fa7dd9022c26228a79dd75a54a..7564fc7f0f2ad7bfc38253392412b95865fac55f 100644 (file)
@@ -48,6 +48,7 @@
 #include <climits>
 #include <locale>
 #include <memory>
+#include <optional>
 
 #include "cls/lock/cls_lock_client.h"
 #include "include/compat.h"
@@ -115,7 +116,7 @@ void usage(ostream& out)
 "   listomapvals <obj-name>          list the keys and vals in the object map \n"
 "   getomapval <obj-name> <key> [file] show the value for the specified key\n"
 "                                    in the object's object map\n"
-"   setomapval <obj-name> <key> <val>\n"
+"   setomapval <obj-name> <key> <val | --input-file file>\n"
 "   rmomapkey <obj-name> <key>\n"
 "   clearomap <obj-name> [obj-name2 obj-name3...] clear all the omap keys for the specified objects\n"
 "   getomapheader <obj-name> [file]\n"
@@ -132,6 +133,7 @@ void usage(ostream& out)
 "   tier-promote <obj-name>         promote the object to the base tier\n"
 "   unset-manifest <obj-name>       unset redirect or chunked object\n"
 "   tier-flush <obj-name>           flush the chunked object\n"
+"   tier-evict <obj-name>           evict the chunked object\n"
 "\n"
 "IMPORT AND EXPORT\n"
 "   export [filename]\n"
@@ -169,7 +171,7 @@ void usage(ostream& out)
 "   cache-try-flush-evict-all        try-flush+evict all objects\n"
 "\n"
 "GLOBAL OPTIONS:\n"
-"   --object_locator object_locator\n"
+"   --object-locator object_locator\n"
 "        set object_locator for operation\n"
 "   -p pool\n"
 "   --pool=pool\n"
@@ -186,9 +188,13 @@ void usage(ostream& out)
 "        set the object size for put/get ops and for write benchmarking\n"
 "   --max-objects\n"
 "        set the max number of objects for write benchmarking\n"
+"   --obj-name-file file\n"
+"        use the content of the specified file in place of <obj-name>\n"
 "   -s name\n"
 "   --snap name\n"
 "        select given snap name for (read) IO\n"
+"   --input-file file\n"
+"        use the content of the specified file in place of <val>\n"
 "   --create\n"
 "        create the pool or directory that was specified\n"
 "   -N namespace\n"
@@ -237,11 +243,16 @@ void usage(ostream& out)
 "   --read-percent                   percent of operations that are read\n"
 "   --target-throughput              target throughput (in bytes)\n"
 "   --run-length                     total time (in seconds)\n"
-"   --offset-align                   at what boundary to align random op offsets"
+"   --offset-align                   at what boundary to align random op offsets\n"
+"\n"
 "CACHE POOLS OPTIONS:\n"
 "   --with-clones                    include clones when doing flush or evict\n"
+"\n"
 "OMAP OPTIONS:\n"
-"    --omap-key-file file            read the omap key from a file\n";
+"    --omap-key-file file            read the omap key from a file\n"
+"\n"
+"GENERIC OPTIONS:\n";
+  generic_client_usage();
 }
 
 namespace detail {
@@ -437,7 +448,7 @@ static int dump_data(std::string const &filename, bufferlist const &data)
   if (filename == "-") {
     fd = STDOUT_FILENO;
   } else {
-    fd = TEMP_FAILURE_RETRY(::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644));
+    fd = TEMP_FAILURE_RETRY(::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644));
     if (fd < 0) {
       int err = errno;
       cerr << "failed to open file: " << cpp_strerror(err) << std::endl;
@@ -455,15 +466,13 @@ static int dump_data(std::string const &filename, bufferlist const &data)
 }
 
 
-static int do_get(IoCtx& io_ctx, const char *objname, const char *outfile, unsigned op_size, [[maybe_unused]] const bool use_striper)
+static int do_get(IoCtx& io_ctx, const std::string& oid, const char *outfile, unsigned op_size, [[maybe_unused]] const bool use_striper)
 {
-  string oid(objname);
-
   int fd;
   if (strcmp(outfile, "-") == 0) {
     fd = STDOUT_FILENO;
   } else {
-    fd = TEMP_FAILURE_RETRY(::open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0644));
+    fd = TEMP_FAILURE_RETRY(::open(outfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644));
     if (fd < 0) {
       int err = errno;
       cerr << "failed to open file: " << cpp_strerror(err) << std::endl;
@@ -551,16 +560,15 @@ static int do_copy_pool(Rados& rados, const char *src_pool, const char *target_p
 }
 
 static int do_put(IoCtx& io_ctx, 
-            const char *objname, const char *infile, int op_size,
+            const std::string& oid, const char *infile, int op_size,
             uint64_t obj_offset, bool create_object,
             const bool use_striper)
 {
-  string oid(objname);
   bool stdio = (strcmp(infile, "-") == 0);
   int ret = 0;
   int fd = STDIN_FILENO;
   if (!stdio)
-    fd = open(infile, O_RDONLY);
+    fd = open(infile, O_RDONLY|O_BINARY);
   if (fd < 0) {
     cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl;
     return 1;
@@ -613,15 +621,14 @@ static int do_put(IoCtx& io_ctx,
 }
 
 static int do_append(IoCtx& io_ctx, 
-                  const char *objname, const char *infile, int op_size,
+                  const std::string& oid, const char *infile, int op_size,
                   const bool use_striper)
 {
-  string oid(objname);
   bool stdio = (strcmp(infile, "-") == 0);
   int ret = 0;
   int fd = STDIN_FILENO;
   if (!stdio)
-    fd = open(infile, O_RDONLY);
+    fd = open(infile, O_RDONLY|O_BINARY);
   if (fd < 0) {
     cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl;
     return 1;
@@ -1179,7 +1186,7 @@ static int do_lock_cmd(std::vector<const char*> &nargs,
   string lock_cookie;
   string lock_description;
   int lock_duration = 0;
-  ClsLockType lock_type = LOCK_EXCLUSIVE;
+  ClsLockType lock_type = ClsLockType::EXCLUSIVE;
 
   map<string, string>::const_iterator i;
   i = opts.find("lock-tag");
@@ -1204,9 +1211,9 @@ static int do_lock_cmd(std::vector<const char*> &nargs,
   if (i != opts.end()) {
     const string& type_str = i->second;
     if (type_str.compare("exclusive") == 0) {
-      lock_type = LOCK_EXCLUSIVE;
+      lock_type = ClsLockType::EXCLUSIVE;
     } else if (type_str.compare("shared") == 0) {
-      lock_type = LOCK_SHARED;
+      lock_type = ClsLockType::SHARED;
     } else {
       cerr << "unknown lock type was specified, aborting" << std::endl;
       return -EINVAL;
@@ -1243,7 +1250,7 @@ static int do_lock_cmd(std::vector<const char*> &nargs,
 
   if (cmd.compare("info") == 0) {
     map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t> lockers;
-    ClsLockType type = LOCK_NONE;
+    ClsLockType type = ClsLockType::NONE;
     string tag;
     int ret = rados::cls::lock::get_lock_info(ioctx, oid, lock_name, &lockers, &type, &tag);
     if (ret < 0) {
@@ -1281,7 +1288,7 @@ static int do_lock_cmd(std::vector<const char*> &nargs,
     l.set_description(lock_description);
     int ret;
     switch (lock_type) {
-    case LOCK_SHARED:
+    case ClsLockType::SHARED:
       ret = l.lock_shared(ioctx, oid);
       break;
     default:
@@ -1830,6 +1837,16 @@ static int do_get_inconsistent_cmd(const std::vector<const char*> &nargs,
   return ret;
 }
 
+static std::string prettify(const std::string& s)
+{
+  if (std::find_if_not(s.begin(), s.end(),
+                       (int (*)(int))isprint) != s.end()) {
+    return "(binary key)";
+  } else {
+    return s;
+  }
+}
+
 /**********************************************
 
 **********************************************/
@@ -1880,9 +1897,9 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   unique_ptr<Formatter> formatter = nullptr;
   bool pretty_format = false;
   const char *output = NULL;
-  bool omap_key_valid = false;
-  std::string omap_key;
-  std::string omap_key_pretty;
+  std::optional<std::string> omap_key;
+  std::optional<std::string> obj_name;
+  std::string input_file;
   bool with_reference = false;
 
   Rados rados;
@@ -2094,14 +2111,18 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cerr << err << std::endl;
       return 1;
     }
-
-    omap_key_valid = true;
     omap_key = std::string(indata.c_str(), indata.length());
-    omap_key_pretty = omap_key;
-    if (std::find_if_not(omap_key.begin(), omap_key.end(),
-                         (int (*)(int))isprint) != omap_key.end()) {
-        omap_key_pretty = "(binary key)";
+  }
+  i = opts.find("obj-name-file");
+  if (i != opts.end()) {
+    string err;
+    bufferlist indata;
+    ret = indata.read_file(i->second.c_str(), &err);
+    if (ret < 0) {
+      cerr << err << std::endl;
+      return 1;
     }
+    obj_name = std::string(indata.c_str(), indata.length());
   }
   i = opts.find("offset_align");
   if (i != opts.end()) {
@@ -2113,6 +2134,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   if (i != opts.end()) {
     with_reference = true;
   }
+  i = opts.find("input_file");
+  if (i != opts.end()) {
+    input_file = i->second;
+  }
 
   // open rados
   ret = rados.init_with_context(g_ceph_context);
@@ -2216,7 +2241,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   }
   if (oloc.size()) {
     if (!pool_name) {
-      cerr << "pool name must be specified with --object_locator" << std::endl;
+      cerr << "pool name must be specified with --object-locator" << std::endl;
       return 1;
     }
     io_ctx.locator_set_key(oloc);
@@ -2478,15 +2503,17 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "mapext") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     std::map<uint64_t,uint64_t> m;
-    ret = io_ctx.mapext(oid, 0, -1, m);
+    ret = io_ctx.mapext(*obj_name, 0, -1, m);
     if (ret < 0) {
-      cerr << "mapext error on " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "mapext error on " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
     std::map<uint64_t,uint64_t>::iterator iter;
@@ -2495,117 +2522,148 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "stat") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     uint64_t size;
     time_t mtime;
 
-    ret = detail::stat(io_ctx, oid, size, mtime, use_striper);
+    ret = detail::stat(io_ctx, *obj_name, size, mtime, use_striper);
 
     if (ret < 0) {
-      cerr << " error stat-ing " << pool_name << "/" << oid << ": "
+      cerr << " error stat-ing " << pool_name << "/" << prettify(*obj_name) << ": "
            << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
       utime_t t(mtime, 0);
-      cout << pool_name << "/" << oid
+      cout << pool_name << "/" << prettify(*obj_name)
            << " mtime " << t << ", size " << size << std::endl;
     }
   }
   else if (strcmp(nargs[0], "stat2") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     uint64_t size;
     struct timespec mtime;
 
-    ret = detail::stat2(io_ctx, oid, size, mtime, use_striper);
+    ret = detail::stat2(io_ctx, *obj_name, size, mtime, use_striper);
 
     if (ret < 0) {
-      cerr << " error stat-ing " << pool_name << "/" << oid << ": "
+      cerr << " error stat-ing " << pool_name << "/" << prettify(*obj_name) << ": "
           << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
       utime_t t(mtime);
-      cout << pool_name << "/" << oid
+      cout << pool_name << "/" << prettify(*obj_name)
           << " mtime " << t << ", size " << size << std::endl;
     }
   } 
   else if (strcmp(nargs[0], "touch") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
     time_t timestamp = time(NULL);
-    if (nargs.size() > 2) {
+    if (nargs.size() > (obj_name ? 1 : 2)) {
       char* endptr = NULL;
-      timestamp = static_cast<time_t>(strtoll(nargs[2], &endptr, 10));
+      timestamp = static_cast<time_t>(strtoll(nargs[obj_name ? 1 : 2], &endptr, 10));
       if (*endptr) {
-        cerr << "Invalid value for timestamp: '" << nargs[2] << "'" << std::endl;
+        cerr << "Invalid value for timestamp: '" << nargs[obj_name ? 1 : 2] << "'" << std::endl;
         ret = -EINVAL;
         return 1;
       }
     }
-    
+    if (!obj_name) {
+       obj_name = nargs[1];
+    }
     ObjectWriteOperation op;
     op.create(false);
     op.mtime(&timestamp);
-    ret = io_ctx.operate(oid, &op);
+    ret = io_ctx.operate(*obj_name, &op);
     if (ret < 0) {
-      cerr << " error touch-ing " << pool_name << "/" << oid << ": "
+      cerr << " error touch-ing " << pool_name << "/" << prettify(*obj_name) << ": "
           << cpp_strerror(ret) << std::endl;
       return 1;
     }
   }
   else if (strcmp(nargs[0], "get") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
-    ret = do_get(io_ctx, nargs[1], nargs[2], op_size, use_striper);
+    const char* out_filename;
+    if (obj_name) {
+      out_filename = nargs[1];
+    } else {
+      obj_name = nargs[1];
+      out_filename = nargs[2];
+    }
+    ret = do_get(io_ctx, *obj_name, out_filename, op_size, use_striper);
     if (ret < 0) {
-      cerr << "error getting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error getting " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
   }
   else if (strcmp(nargs[0], "put") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
+    const char* in_filename;
+    if (obj_name) {
+      in_filename = nargs[1];
+    } else {
+      obj_name = nargs[1];
+      in_filename = nargs[2];
+    }
     bool create_object = !obj_offset_specified;
-    ret = do_put(io_ctx, nargs[1], nargs[2], op_size, obj_offset, create_object, use_striper);
+    ret = do_put(io_ctx, *obj_name, in_filename, op_size, obj_offset, create_object, use_striper);
     if (ret < 0) {
-      cerr << "error putting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error putting " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
   }
   else if (strcmp(nargs[0], "append") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
-    ret = do_append(io_ctx, nargs[1], nargs[2], op_size, use_striper);
+    const char* in_filename;
+    if (obj_name) {
+      in_filename = nargs[1];
+    } else {
+      obj_name = nargs[1];
+      in_filename = nargs[2];
+    }
+    ret = do_append(io_ctx, *obj_name, in_filename, op_size, use_striper);
     if (ret < 0) {
-      cerr << "error appending " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error appending " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
   }
   else if (strcmp(nargs[0], "truncate") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
 
-    string oid(nargs[1]);
     char* endptr = NULL;
-    long size = strtoll(nargs[2], &endptr, 10);
+    long size;
+    if (!obj_name) {
+      obj_name = nargs[1];
+      size = strtoll(nargs[2], &endptr, 10);
+    } else {
+      size = strtoll(nargs[1], &endptr, 10);
+    }
     if (*endptr) {
       cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
       ret = -EINVAL;
@@ -2617,27 +2675,26 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       return 1;
     }
 
-    ret = detail::trunc(io_ctx, oid, size, use_striper);
+    ret = detail::trunc(io_ctx, *obj_name, size, use_striper);
 
     if (ret < 0) {
       cerr << "error truncating oid "
-          << oid << " to " << size << ": "
+          << prettify(*obj_name) << " to " << size << ": "
           << cpp_strerror(ret) << std::endl;
     } else {
       ret = 0;
     }
   }
   else if (strcmp(nargs[0], "setxattr") == 0) {
-    if (!pool_name || nargs.size() < 3 || nargs.size() > 4) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3) ||
+       nargs.size() > (obj_name ? 3 : 4)) {
       usage(cerr);
       return 1;
     }
-
-    string oid(nargs[1]);
-    string attr_name(nargs[2]);
+    string attr_name(nargs[obj_name ? 1 : 2]);
     bufferlist bl;
-    if (nargs.size() == 4) {
-      string attr_val(nargs[3]);
+    if (nargs.size() == (obj_name ? 3 : 4)) {
+      string attr_val(nargs[obj_name ? 2 : 3]);
       bl.append(attr_val.c_str(), attr_val.length());
     } else {
       do {
@@ -2646,30 +2703,33 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
          return 1;
       } while (ret > 0);
     }
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
 
-    ret = detail::setxattr(io_ctx, oid, attr_name, bl, use_striper);
+    ret = detail::setxattr(io_ctx, *obj_name, attr_name, bl, use_striper);
 
     if (ret < 0) {
-      cerr << "error setting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error setting xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
     else
       ret = 0;
   }
   else if (strcmp(nargs[0], "getxattr") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
-
-    string oid(nargs[1]);
-    string attr_name(nargs[2]);
-
+    string attr_name(nargs[obj_name ? 1 : 2]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     bufferlist bl;
-    ret = detail::getxattr(io_ctx, oid, attr_name, bl, use_striper);
+    ret = detail::getxattr(io_ctx, *obj_name, attr_name, bl, use_striper);
 
     if (ret < 0) {
-      cerr << "error getting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error getting xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
     else
@@ -2677,34 +2737,36 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     string s(bl.c_str(), bl.length());
     cout << s;
   } else if (strcmp(nargs[0], "rmxattr") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
 
-    string oid(nargs[1]);
-    string attr_name(nargs[2]);
-
-    ret = detail::rmxattr(io_ctx, oid, attr_name, use_striper);
+    string attr_name(nargs[obj_name ? 1 : 2]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
+    ret = detail::rmxattr(io_ctx, *obj_name, attr_name, use_striper);
 
     if (ret < 0) {
-      cerr << "error removing xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error removing xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
   } else if (strcmp(nargs[0], "listxattr") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     bufferlist bl;
     map<std::string, bufferlist> attrset;
 
-    ret = detail::getxattrs(io_ctx, oid, attrset, use_striper);
+    ret = detail::getxattrs(io_ctx, *obj_name, attrset, use_striper);
 
     if (ret < 0) {
-      cerr << "error getting xattr set " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error getting xattr set " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
 
@@ -2713,21 +2775,21 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cout << iter->first << std::endl;
     }
   } else if (strcmp(nargs[0], "getomapheader") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-
-    string oid(nargs[1]);
     string outfile;
-    if (nargs.size() >= 3) {
-      outfile = nargs[2];
+    if (nargs.size() >= (obj_name ? 2 : 3)) {
+      outfile = nargs[obj_name ? 1 : 2];
+    }
+    if (!obj_name) {
+      obj_name = nargs[1];
     }
-
     bufferlist header;
-    ret = io_ctx.omap_get_header(oid, &header);
+    ret = io_ctx.omap_get_header(*obj_name, &header);
     if (ret < 0) {
-      cerr << "error getting omap header " << pool_name << "/" << oid
+      cerr << "error getting omap header " << pool_name << "/" << prettify(*obj_name)
           << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
@@ -2742,40 +2804,47 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       ret = 0;
     }
   } else if (strcmp(nargs[0], "setomapheader") == 0) {
-    if (!pool_name || nargs.size() < 3) {
+    if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) {
       usage(cerr);
       return 1;
     }
 
-    string oid(nargs[1]);
-    string val(nargs[2]);
-
     bufferlist bl;
-    bl.append(val);
-
-    ret = io_ctx.omap_set_header(oid, bl);
+    if (!obj_name) {
+      obj_name = nargs[1];
+      bl.append(nargs[2]); // val
+    } else {
+      bl.append(nargs[1]); // val
+    }
+    ret = io_ctx.omap_set_header(*obj_name, bl);
     if (ret < 0) {
-      cerr << "error setting omap value " << pool_name << "/" << oid
+      cerr << "error setting omap value " << pool_name << "/" << prettify(*obj_name)
           << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
       ret = 0;
     }
   } else if (strcmp(nargs[0], "setomapval") == 0) {
-    uint32_t min_args = (omap_key_valid ? 2 : 3);
+    uint32_t min_args = (omap_key ? 2 : 3);
     if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) {
       usage(cerr);
       return 1;
     }
 
     string oid(nargs[1]);
-    if (!omap_key_valid) {
+    if (!omap_key) {
       omap_key = nargs[2];
-      omap_key_pretty = omap_key;
     }
 
     bufferlist bl;
-    if (nargs.size() > min_args) {
+    if (!input_file.empty()) {
+      string err;
+      ret = bl.read_file(input_file.c_str(), &err);
+      if (ret < 0) {
+        cerr << "error reading file " << input_file.c_str() << ": " << err << std::endl;
+        return 1;
+      }
+    } else if (nargs.size() > min_args) {
       string val(nargs[min_args]);
       bl.append(val);
     } else {
@@ -2788,48 +2857,50 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
 
     map<string, bufferlist> values;
-    values[omap_key] = bl;
+    values[*omap_key] = bl;
 
     ret = io_ctx.omap_set(oid, values);
     if (ret < 0) {
       cerr << "error setting omap value " << pool_name << "/" << oid << "/"
-           << omap_key_pretty << ": " << cpp_strerror(ret) << std::endl;
+           << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
       ret = 0;
     }
   } else if (strcmp(nargs[0], "getomapval") == 0) {
-    uint32_t min_args = (omap_key_valid ? 2 : 3);
+    uint32_t min_args = (omap_key ? (obj_name ? 1 : 2)
+                                 : (obj_name ? 2 : 3));
     if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) {
       usage(cerr);
       return 1;
     }
 
-    string oid(nargs[1]);
-    if (!omap_key_valid) {
-      omap_key = nargs[2];
-      omap_key_pretty = omap_key;
+    if (!omap_key) {
+      omap_key = nargs[obj_name ? 1 : 2];
     }
 
     set<string> keys;
-    keys.insert(omap_key);
+    keys.insert(*omap_key);
 
     std::string outfile;
     if (nargs.size() > min_args) {
       outfile = nargs[min_args];
     }
+    if (!obj_name) {
+       obj_name = nargs[1];
+    }
 
     map<string, bufferlist> values;
-    ret = io_ctx.omap_get_vals_by_keys(oid, keys, &values);
+    ret = io_ctx.omap_get_vals_by_keys(*obj_name, keys, &values);
     if (ret < 0) {
-      cerr << "error getting omap value " << pool_name << "/" << oid << "/"
-          << omap_key_pretty << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error getting omap value " << pool_name << "/" << prettify(*obj_name) << "/"
+          << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
       ret = 0;
     }
 
-    if (values.size() && values.begin()->first == omap_key) {
+    if (values.size() && values.begin()->first == *omap_key) {
       if (!outfile.empty()) {
        cerr << "Writing to " << outfile << std::endl;
        dump_data(outfile, values.begin()->second);
@@ -2840,62 +2911,70 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       }
       ret = 0;
     } else {
-      cout << "No such key: " << pool_name << "/" << oid << "/"
-           << omap_key_pretty << std::endl;
+      cout << "No such key: " << pool_name << "/" << prettify(*obj_name) << "/"
+           << prettify(*omap_key) << std::endl;
       return 1;
     }
   } else if (strcmp(nargs[0], "rmomapkey") == 0) {
-    uint32_t num_args = (omap_key_valid ? 2 : 3);
+    uint32_t num_args = (omap_key ? (obj_name ? 1 : 2)
+                                 : (obj_name ? 2 : 3));
     if (!pool_name || nargs.size() != num_args) {
       usage(cerr);
       return 1;
     }
 
-    string oid(nargs[1]);
-    if (!omap_key_valid) {
-      omap_key = nargs[2];
-      omap_key_pretty = omap_key;
+    if (!omap_key) {
+      omap_key = nargs[obj_name ? 1 : 2];
+    }
+    if (!obj_name) {
+      obj_name = nargs[1];
     }
     set<string> keys;
-    keys.insert(omap_key);
+    keys.insert(*omap_key);
 
-    ret = io_ctx.omap_rm_keys(oid, keys);
+    ret = io_ctx.omap_rm_keys(*obj_name, keys);
     if (ret < 0) {
-      cerr << "error removing omap key " << pool_name << "/" << oid << "/"
-          << omap_key_pretty << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error removing omap key " << pool_name << "/" << prettify(*obj_name) << "/"
+          << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     } else {
       ret = 0;
     }
   } else if (strcmp(nargs[0], "clearomap") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
+    // strip nargs[0] which is "clearomap"
+    std::vector<std::string> oids(std::next(std::begin(nargs)),
+                                  std::end(nargs));
+    if (obj_name) {
+      oids.push_back(*obj_name);
+    }
 
-    for (unsigned i=1; i < nargs.size(); i++){
-      string oid(nargs[i]);
+    for (const auto& oid : oids) {
       ret = io_ctx.omap_clear(oid);
       if (ret < 0) {
-        cerr << "error clearing omap keys " << pool_name << "/" << oid << "/"
+        cerr << "error clearing omap keys " << pool_name << "/" << prettify(*obj_name) << "/"
              << cpp_strerror(ret) << std::endl;
         return 1;
       }
     }
     ret = 0;
   } else if (strcmp(nargs[0], "listomapvals") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     string last_read = "";
     do {
       map<string, bufferlist> values;
-      ret = io_ctx.omap_get_vals(oid, last_read, MAX_OMAP_BYTES_PER_REQUEST, &values);
+      ret = io_ctx.omap_get_vals(*obj_name, last_read, MAX_OMAP_BYTES_PER_REQUEST, &values);
       if (ret < 0) {
-       cerr << "error getting omap keys " << pool_name << "/" << oid << ": "
+       cerr << "error getting omap keys " << pool_name << "/" << prettify(*obj_name) << ": "
             << cpp_strerror(ret) << std::endl;
        return 1;
       }
@@ -2922,6 +3001,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = 0;
   }
   else if (strcmp(nargs[0], "cp") == 0) {
+    // XXX: binary names aren't supported for this operation
     if (!pool_name) {
       usage(cerr);
       return 1;
@@ -2968,38 +3048,42 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       return 1;
     }
   } else if (strcmp(nargs[0], "rm") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    vector<const char *>::iterator iter = nargs.begin();
-    ++iter;
-    for (; iter != nargs.end(); ++iter) {
-      const string & oid = *iter;
-
-    if (forcefull) {
-        ret = detail::remove(io_ctx, oid, (CEPH_OSD_FLAG_FULL_FORCE |
-                             CEPH_OSD_FLAG_FULL_TRY), use_striper);
-    } else {
-        ret = detail::remove(io_ctx, oid, use_striper);
+    // strip nargs[0] which is "rm"
+    std::vector<std::string> oids(std::next(std::begin(nargs)),
+                                  std::end(nargs));
+    if (obj_name) {
+      oids.push_back(*obj_name);
     }
+    for (const auto& oid : oids) {
+      if (forcefull) {
+          ret = detail::remove(io_ctx, oid, (CEPH_OSD_FLAG_FULL_FORCE |
+                               CEPH_OSD_FLAG_FULL_TRY), use_striper);
+      } else {
+          ret = detail::remove(io_ctx, oid, use_striper);
+      }
 
-    if (ret < 0) {
-        string name = (nspace.size() ? nspace + "/" : "" ) + oid;
-        cerr << "error removing " << pool_name << ">" << name << ": " << cpp_strerror(ret) << std::endl;
-        return 1;
+      if (ret < 0) {
+          string name = (nspace.size() ? nspace + "/" : "" ) + prettify(oid);
+          cerr << "error removing " << pool_name << ">" << name << ": " << cpp_strerror(ret) << std::endl;
+          return 1;
       }
     }
   }
   else if (strcmp(nargs[0], "create") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
-    ret = io_ctx.create(oid, true);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
+    ret = io_ctx.create(*obj_name, true);
     if (ret < 0) {
-      cerr << "error creating " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error creating " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
   }
@@ -3292,27 +3376,30 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       }
     }
   } else if (strcmp(nargs[0], "set-alloc-hint") == 0) {
-    if (!pool_name || nargs.size() < 4) {
+    // cmd, [oid, ] obj_size, write_size
+    if (!pool_name || nargs.size() < (obj_name ? 3 : 4)) {
       usage(cerr);
       return 1;
     }
     string err;
-    string oid(nargs[1]);
-    uint64_t expected_object_size = strict_strtoll(nargs[2], 10, &err);
+    uint64_t expected_object_size = strict_strtoll(nargs[obj_name ? 1 : 2], 10, &err);
     if (!err.empty()) {
       cerr << "couldn't parse expected_object_size: " << err << std::endl;
       usage(cerr);
       return 1;
     }
-    uint64_t expected_write_size = strict_strtoll(nargs[3], 10, &err);
+    uint64_t expected_write_size = strict_strtoll(nargs[obj_name ? 2 : 3], 10, &err);
     if (!err.empty()) {
       cerr << "couldn't parse expected_write_size: " << err << std::endl;
       usage(cerr);
       return 1;
     }
-    ret = io_ctx.set_alloc_hint(oid, expected_object_size, expected_write_size);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
+    ret = io_ctx.set_alloc_hint(*obj_name, expected_object_size, expected_write_size);
     if (ret < 0) {
-      cerr << "error setting alloc-hint " << pool_name << "/" << oid << ": "
+      cerr << "error setting alloc-hint " << pool_name << "/" << prettify(*obj_name) << ": "
            << cpp_strerror(ret) << std::endl;
       return 1;
     }
@@ -3357,19 +3444,21 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     lg.run();
     lg.cleanup();
   } else if (strcmp(nargs[0], "listomapkeys") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     string last_read;
     bool more = true;
     do {
       set<string> out_keys;
-      ret = io_ctx.omap_get_keys2(nargs[1], last_read, MAX_OMAP_BYTES_PER_REQUEST, &out_keys, &more);
+      ret = io_ctx.omap_get_keys2(*obj_name, last_read, MAX_OMAP_BYTES_PER_REQUEST, &out_keys, &more);
       if (ret < 0) {
         cerr << "error getting omap key set " << pool_name << "/"
-             << nargs[1] << ": "  << cpp_strerror(ret) << std::endl;
+             << prettify(*obj_name) << ": "  << cpp_strerror(ret) << std::endl;
         return 1;
       }
 
@@ -3409,18 +3498,19 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cout << "watcher=" << i->addr << " client." << i->watcher_id << " cookie=" << i->cookie << std::endl;
     }
   } else if (strcmp(nargs[0], "listsnaps") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
+    if (!obj_name) {
+       obj_name = nargs[1];
+    }
 
-    string oid(nargs[1]);
     snap_set_t ls;
-
     io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
-    ret = io_ctx.list_snaps(oid, &ls);
+    ret = io_ctx.list_snaps(*obj_name, &ls);
     if (ret < 0) {
-      cerr << "error listing snap shots " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
+      cerr << "error listing snap shots " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl;
       return 1;
     }
     else
@@ -3441,10 +3531,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
     if (formatter) {
       formatter->open_object_section("object");
-      formatter->dump_string("name", oid);
+      formatter->dump_string("name", *obj_name);
       formatter->open_array_section("clones");
     } else {
-      cout << oid << ":" << std::endl;
+      cout << prettify(*obj_name) << ":" << std::endl;
       cout << "cloneid snaps   size    overlap" << std::endl;
     }
 
@@ -3550,17 +3640,19 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
     ret = do_get_inconsistent_cmd<inconsistent_snapset_t>(nargs, rados, *formatter);
   } else if (strcmp(nargs[0], "cache-flush") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     if (with_clones) {
       snap_set_t ls;
       io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
-      ret = io_ctx.list_snaps(oid, &ls);
+      ret = io_ctx.list_snaps(*obj_name, &ls);
       if (ret < 0) {
-        cerr << "error listing snapshots " << pool_name << "/" << oid << ": "
+        cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": "
              << cpp_strerror(ret) << std::endl;
         return 1;
       }
@@ -3569,33 +3661,35 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (snapid != CEPH_NOSNAP && ci->cloneid > snapid)
           break;
         io_ctx.snap_set_read(ci->cloneid);
-        ret = do_cache_flush(io_ctx, oid);
+        ret = do_cache_flush(io_ctx, *obj_name);
         if (ret < 0) {
-          cerr << "error from cache-flush " << oid << ": "
+          cerr << "error from cache-flush " << prettify(*obj_name) << ": "
                << cpp_strerror(ret) << std::endl;
           return 1;
         }
       }
     } else {
-      ret = do_cache_flush(io_ctx, oid);
+      ret = do_cache_flush(io_ctx, *obj_name);
       if (ret < 0) {
-        cerr << "error from cache-flush " << oid << ": "
+        cerr << "error from cache-flush " << prettify(*obj_name) << ": "
             << cpp_strerror(ret) << std::endl;
         return 1;
       }
     }
   } else if (strcmp(nargs[0], "cache-try-flush") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     if (with_clones) {
       snap_set_t ls;
       io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
-      ret = io_ctx.list_snaps(oid, &ls);
+      ret = io_ctx.list_snaps(*obj_name, &ls);
       if (ret < 0) {
-        cerr << "error listing snapshots " << pool_name << "/" << oid << ": "
+        cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": "
              << cpp_strerror(ret) << std::endl;
         return 1;
       }
@@ -3604,33 +3698,35 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (snapid != CEPH_NOSNAP && ci->cloneid > snapid)
           break;
         io_ctx.snap_set_read(ci->cloneid);
-        ret = do_cache_try_flush(io_ctx, oid);
+        ret = do_cache_try_flush(io_ctx, *obj_name);
         if (ret < 0) {
-          cerr << "error from cache-flush " << oid << ": "
+          cerr << "error from cache-flush " << prettify(*obj_name) << ": "
                << cpp_strerror(ret) << std::endl;
           return 1;
         }
       }
     } else {
-      ret = do_cache_try_flush(io_ctx, oid);
+      ret = do_cache_try_flush(io_ctx, *obj_name);
       if (ret < 0) {
-        cerr << "error from cache-flush " << oid << ": "
+        cerr << "error from cache-flush " << prettify(*obj_name) << ": "
              << cpp_strerror(ret) << std::endl;
         return 1;
       }
     }
   } else if (strcmp(nargs[0], "cache-evict") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     if (with_clones) {
       snap_set_t ls;
       io_ctx.snap_set_read(LIBRADOS_SNAP_DIR);
-      ret = io_ctx.list_snaps(oid, &ls);
+      ret = io_ctx.list_snaps(*obj_name, &ls);
       if (ret < 0) {
-        cerr << "error listing snapshots " << pool_name << "/" << oid << ": "
+        cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": "
              << cpp_strerror(ret) << std::endl;
         return 1;
       }
@@ -3639,17 +3735,17 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (snapid != CEPH_NOSNAP && ci->cloneid > snapid)
           break;
         io_ctx.snap_set_read(ci->cloneid);
-        ret = do_cache_evict(io_ctx, oid);
+        ret = do_cache_evict(io_ctx, *obj_name);
         if (ret < 0) {
-          cerr << "error from cache-flush " << oid << ": "
+          cerr << "error from cache-flush " << prettify(*obj_name) << ": "
                << cpp_strerror(ret) << std::endl;
           return 1;
         }
       }
     } else {
-      ret = do_cache_evict(io_ctx, oid);
+      ret = do_cache_evict(io_ctx, *obj_name);
       if (ret < 0) {
-        cerr << "error from cache-flush " << oid << ": "
+        cerr << "error from cache-flush " << prettify(*obj_name) << ": "
              << cpp_strerror(ret) << std::endl;
         return 1;
       }
@@ -3754,13 +3850,9 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
     IoCtx target_ctx;
     ret = rados.ioctx_create(target, target_ctx);
-    ObjectWriteOperation op;
-    if (with_reference) {
-      op.set_chunk(offset, length, target_ctx, tgt_oid, tgt_offset, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
-    } else {
-      op.set_chunk(offset, length, target_ctx, tgt_oid, tgt_offset);
-    }
-    ret = io_ctx.operate(nargs[1], &op);
+    ObjectReadOperation op;
+    op.set_chunk(offset, length, target_ctx, tgt_oid, tgt_offset, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+    ret = io_ctx.operate(nargs[1], &op, NULL);
     if (ret < 0) {
       cerr << "error set-chunk " << pool_name << "/" << nargs[1] << " " << " offset " << offset
            << " length " << length << " target_pool " << target 
@@ -3768,47 +3860,82 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       return 1;
     }
   } else if (strcmp(nargs[0], "tier-promote") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
-
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     ObjectWriteOperation op;
     op.tier_promote();
-    ret = io_ctx.operate(oid, &op);
+    ret = io_ctx.operate(*obj_name, &op);
     if (ret < 0) {
-      cerr << "error tier-promote " << pool_name << "/" << oid << " : " 
+      cerr << "error tier-promote " << pool_name << "/" << prettify(*obj_name) << " : "
           << cpp_strerror(ret) << std::endl;
       return 1;
     }
   } else if (strcmp(nargs[0], "unset-manifest") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
-
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
     ObjectWriteOperation op;
     op.unset_manifest();
-    ret = io_ctx.operate(oid, &op);
+    ret = io_ctx.operate(*obj_name, &op);
     if (ret < 0) {
-      cerr << "error unset-manifest " << pool_name << "/" << oid << " : " 
+      cerr << "error unset-manifest " << pool_name << "/" << prettify(*obj_name) << " : "
           << cpp_strerror(ret) << std::endl;
       return 1;
     }
   } else if (strcmp(nargs[0], "tier-flush") == 0) {
-    if (!pool_name || nargs.size() < 2) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
       usage(cerr);
       return 1;
     }
-    string oid(nargs[1]);
-
-    ObjectWriteOperation op;
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
+    ObjectReadOperation op;
     op.tier_flush();
-    ret = io_ctx.operate(oid, &op);
+    librados::AioCompletion *completion =
+      librados::Rados::aio_create_completion();
+    io_ctx.aio_operate(*obj_name, completion, &op,
+                      librados::OPERATION_IGNORE_CACHE |
+                      librados::OPERATION_IGNORE_OVERLAY,
+                      NULL);
+    completion->wait_for_complete();
+    ret = completion->get_return_value();
+    completion->release();
+    if (ret < 0) {
+      cerr << "error tier-flush " << pool_name << "/" << prettify(*obj_name) << " : "
+          << cpp_strerror(ret) << std::endl;
+      return 1;
+    }
+  } else if (strcmp(nargs[0], "tier-evict") == 0) {
+    if (!pool_name || (nargs.size() < 2 && !obj_name)) {
+      usage(cerr);
+      return 1;
+    }
+    if (!obj_name) {
+      obj_name = nargs[1];
+    }
+    ObjectReadOperation op;
+    op.tier_evict();
+    librados::AioCompletion *completion =
+      librados::Rados::aio_create_completion();
+    io_ctx.aio_operate(*obj_name, completion, &op,
+                      librados::OPERATION_IGNORE_CACHE |
+                      librados::OPERATION_IGNORE_OVERLAY,
+                      NULL);
+    completion->wait_for_complete();
+    ret = completion->get_return_value();
+    completion->release();
     if (ret < 0) {
-      cerr << "error tier-flush " << pool_name << "/" << oid << " : " 
+      cerr << "error tier-evict " << pool_name << "/" << prettify(*obj_name) << " : "
           << cpp_strerror(ret) << std::endl;
       return 1;
     }
@@ -3823,7 +3950,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (nargs.size() < 2 || std::string(nargs[1]) == "-") {
       file_fd = STDOUT_FILENO;
     } else {
-      file_fd = open(nargs[1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
+      file_fd = open(nargs[1], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
       if (file_fd < 0) {
         cerr << "Error opening '" << nargs[1] << "': "
           << cpp_strerror(file_fd) << std::endl;
@@ -3872,7 +3999,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (filename == "-") {
       file_fd = STDIN_FILENO;
     } else {
-      file_fd = open(filename.c_str(), O_RDONLY);
+      file_fd = open(filename.c_str(), O_RDONLY|O_BINARY);
       if (file_fd < 0) {
         cerr << "Error opening '" << filename << "': "
           << cpp_strerror(file_fd) << std::endl;
@@ -4058,10 +4185,14 @@ int main(int argc, const char **argv)
       opts["with-clones"] = "true";
     } else if (ceph_argparse_witharg(args, i, &val, "--omap-key-file", (char*)NULL)) {
       opts["omap-key-file"] = val;
+    } else if (ceph_argparse_witharg(args, i, &val, "--obj-name-file", (char*)NULL)) {
+      opts["obj-name-file"] = val;
     } else if (ceph_argparse_flag(args, i, "--with-reference", (char*)NULL)) {
       opts["with-reference"] = "true";
     } else if (ceph_argparse_witharg(args, i, &val, "--pgid", (char*)NULL)) {
       opts["pgid"] = val;
+    } else if (ceph_argparse_witharg(args, i, &val, "--input-file", (char*)NULL)) {
+      opts["input_file"] = val;
     } else {
       if (val[0] == '-')
         usage_exit();