]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
tools/rados: always call rados.shutdown() before exit()
authorLi Wang <laurence.liwang@gmail.com>
Tue, 27 Nov 2018 03:35:53 +0000 (03:35 +0000)
committerNathan Cutler <ncutler@suse.com>
Tue, 15 Oct 2019 08:57:30 +0000 (10:57 +0200)
When connected to ceph cluster, if call exit(1) directly, will cause the finisher
thread segmentation fault as follows,

Caught signal (Segmentation fault) **in thread 7f45377fe700 thread_name:fn_anonymous

run 'rados mapext' without other arguments could easily get it. This patch fixes it
by calling rados.shutdown() before exit()

Fixes: http://tracker.ceph.com/issues/36732
Signed-off-by: Li Wang <laurence.liwang@gmail.com>
(cherry picked from commit 2c149262888c50beb9f480a6cd78f77fd5920d1c)

Conflicts:
src/tools/rados/rados.cc
- revert "std::make_unique" change that, in master, should have been included in
  3804f52b109558591d699609749a789b5cfc72b9 (which is not being backported)

src/tools/rados/rados.cc

index dcc506c2a204a356a37cc2877f3e39a1884c1865..ce2b83ec6d13873e1c4c2494fd4736b8bfc88ff5 100644 (file)
@@ -2100,27 +2100,26 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   boost::optional<pg_t> pgid(i != opts.end(), std::move(pg_t()));
   if (pgid && (!pgid->parse(i->second.c_str()) || (pool_name && rados.pool_lookup(pool_name) != pgid->pool()))) {
     cerr << "invalid pgid" << std::endl;
-    ret = -1;
-    goto out;
+    return 1;
   }
 
   // open rados
   ret = rados.init_with_context(g_ceph_context);
   if (ret < 0) {
      cerr << "couldn't initialize rados: " << cpp_strerror(ret) << std::endl;
-     goto out;
+     return 1;
   }
 
   ret = rados.connect();
   if (ret) {
      cerr << "couldn't connect to cluster: " << cpp_strerror(ret) << std::endl;
-     ret = -1;
-     goto out;
+     return 1;
   }
 
   if (create_pool && !pool_name) {
     cerr << "--create-pool requested but pool_name was not specified!" << std::endl;
-    usage_exit();
+    usage(cerr);
+    return 1;
   }
 
   if (create_pool) {
@@ -2128,7 +2127,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error creating pool " << pool_name << ": "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
 
@@ -2139,7 +2138,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cerr << "error opening pool "
            << (pool_name ? pool_name : std::string("with id ") + std::to_string(pgid->pool())) << ": "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
 
    // align op_size
@@ -2149,7 +2148,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error checking pool alignment requirement"
           << cpp_strerror(ret) << std::endl;
-        goto out;      
+        return 1;
       }
 
       if (requires) {
@@ -2158,7 +2157,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (ret < 0) {
           cerr << "error getting pool alignment"
             << cpp_strerror(ret) << std::endl;
-          goto out;    
+          return 1;
         }
 
         const uint64_t prev_op_size = op_size;
@@ -2178,7 +2177,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (0 != ret) {
           cerr << "error opening pool " << pool_name << " with striper interface: "
                << cpp_strerror(ret) << std::endl;
-             goto out;
+             return 1;
       }
       use_striper = true;
     }
@@ -2189,20 +2188,18 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   if (snapname) {
     if (!pool_name) {
       cerr << "pool name must be specified with --snap" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
     ret = io_ctx.snap_lookup(snapname, &snapid);
     if (ret < 0) {
       cerr << "error looking up snap '" << snapname << "': " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
   if (oloc.size()) {
     if (!pool_name) {
       cerr << "pool name must be specified with --object_locator" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
     io_ctx.locator_set_key(oloc);
   }
@@ -2210,8 +2207,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   if (opts.find("namespace") != opts.end()) {
     if (!pool_name) {
       cerr << "pool name must be specified with --namespace" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
     io_ctx.set_namespace(nspace);
   // Use wildcard if --all specified and --default NOT specified
@@ -2222,15 +2218,14 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   if (snapid != CEPH_NOSNAP) {
     if (!pool_name) {
       cerr << "pool name must be specified with --snapid" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
     string name;
     ret = io_ctx.snap_get_name(snapid, &name);
     if (ret < 0) {
       cerr << "snapid " << snapid << " doesn't exist in pool "
           << io_ctx.get_pool_name() << std::endl;
-      goto out;
+      return 1;
     }
     io_ctx.snap_set_read(snapid);
     cout << "selected snap " << snapid << " '" << name << "'" << std::endl;
@@ -2244,7 +2239,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = rados.pool_list(vec);
     if (ret < 0) {
       cerr << "error listing pools: " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     for (list<string>::iterator i = vec.begin(); i != vec.end(); ++i)
       cout << *i << std::endl;
@@ -2257,7 +2252,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       ret = rados.pool_list(vec);
       if (ret < 0) {
        cerr << "error listing pools: " << cpp_strerror(ret) << std::endl;
-       goto out;
+       return 1;
       }
     } else {
       vec.push_back(pool_name);
@@ -2267,7 +2262,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = rados.get_pool_stats(vec, stats);
     if (ret < 0) {
       cerr << "error fetching pool stats: " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
 
     TextTable tab;
@@ -2342,7 +2337,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = rados.cluster_stat(tstats);
     if (ret < 0) {
       cerr << "error getting total cluster usage: " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     if (!formatter) {
       cout << std::endl;
@@ -2368,8 +2363,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   else if (strcmp(nargs[0], "ls") == 0) {
     if (!pool_name && !pgid) {
       cerr << "either pool name or pg id needs to be specified" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
 
     if (wildcard)
@@ -2377,8 +2371,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     bool use_stdout = (!output && (nargs.size() < 2 || (strcmp(nargs[1], "-") == 0)));
     if (!use_stdout && !output) {
       cerr << "Please use --output to specify the output file name" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
     ostream *outstream;
     if(use_stdout)
@@ -2432,8 +2425,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       }
       catch (const std::runtime_error& e) {
        cerr << e.what() << std::endl;
-       ret = -1;
-       goto out;
+       return 1;
       }
     }
     if (formatter) {
@@ -2465,14 +2457,16 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
                << " to " << new_auid << std::endl;
   }
   else if (strcmp(nargs[0], "mapext") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     std::map<uint64_t,uint64_t> m;
     ret = io_ctx.mapext(oid, 0, -1, m);
     if (ret < 0) {
       cerr << "mapext error on " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     std::map<uint64_t,uint64_t>::iterator iter;
     for (iter = m.begin(); iter != m.end(); ++iter) {
@@ -2480,8 +2474,10 @@ 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)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     uint64_t size;
     time_t mtime;
@@ -2491,7 +2487,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << " error stat-ing " << pool_name << "/" << oid << ": "
            << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       utime_t t(mtime, 0);
       cout << pool_name << "/" << oid
@@ -2499,8 +2495,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "stat2") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     uint64_t size;
     struct timespec mtime;
@@ -2510,7 +2508,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << " error stat-ing " << pool_name << "/" << oid << ": "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       utime_t t(mtime);
       cout << pool_name << "/" << oid
@@ -2518,8 +2516,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   } 
   else if (strcmp(nargs[0], "touch") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     time_t timestamp = time(NULL);
     if (nargs.size() > 2) {
@@ -2528,7 +2528,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (*endptr) {
         cerr << "Invalid value for timestamp: '" << nargs[2] << "'" << std::endl;
         ret = -EINVAL;
-        goto out;
+        return 1;
       }
     }
     
@@ -2539,39 +2539,47 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << " error touch-ing " << pool_name << "/" << oid << ": "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
   else if (strcmp(nargs[0], "get") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
     ret = do_get(io_ctx, nargs[1], nargs[2], op_size, use_striper);
     if (ret < 0) {
       cerr << "error getting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
   else if (strcmp(nargs[0], "put") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
     ret = do_put(io_ctx, nargs[1], nargs[2], op_size, obj_offset, use_striper);
     if (ret < 0) {
       cerr << "error putting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
   else if (strcmp(nargs[0], "append") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
     ret = do_append(io_ctx, nargs[1], nargs[2], op_size, use_striper);
     if (ret < 0) {
       cerr << "error appending " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
   else if (strcmp(nargs[0], "truncate") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     char* endptr = NULL;
@@ -2579,11 +2587,12 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (*endptr) {
       cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
       ret = -EINVAL;
-      goto out;
+      return 1;
     }
     if (size < 0) {
       cerr << "error, cannot truncate to negative value" << std::endl;
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     ret = detail::trunc(io_ctx, oid, size, use_striper);
@@ -2597,8 +2606,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "setxattr") == 0) {
-    if (!pool_name || nargs.size() < 3 || nargs.size() > 4)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3 || nargs.size() > 4) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     string attr_name(nargs[2]);
@@ -2610,7 +2621,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       do {
        ret = bl.read_fd(STDIN_FILENO, 1024); // from stdin
        if (ret < 0)
-         goto out;
+         return 1;
       } while (ret > 0);
     }
 
@@ -2618,14 +2629,16 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
     if (ret < 0) {
       cerr << "error setting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     else
       ret = 0;
   }
   else if (strcmp(nargs[0], "getxattr") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     string attr_name(nargs[2]);
@@ -2635,15 +2648,17 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
     if (ret < 0) {
       cerr << "error getting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     else
       ret = 0;
     string s(bl.c_str(), bl.length());
     cout << s;
   } else if (strcmp(nargs[0], "rmxattr") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     string attr_name(nargs[2]);
@@ -2652,11 +2667,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
     if (ret < 0) {
       cerr << "error removing xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "listxattr") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     bufferlist bl;
@@ -2666,7 +2683,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
     if (ret < 0) {
       cerr << "error getting xattr set " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
 
     for (map<std::string, bufferlist>::iterator iter = attrset.begin();
@@ -2674,8 +2691,10 @@ 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)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     string outfile;
@@ -2688,7 +2707,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error getting omap header " << pool_name << "/" << oid
           << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       if (!outfile.empty()) {
        cerr << "Writing to " << outfile << std::endl;
@@ -2701,8 +2720,10 @@ 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)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     string val(nargs[2]);
@@ -2714,14 +2735,15 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error setting omap value " << pool_name << "/" << oid
           << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       ret = 0;
     }
   } else if (strcmp(nargs[0], "setomapval") == 0) {
     uint32_t min_args = (omap_key_valid ? 2 : 3);
     if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     string oid(nargs[1]);
@@ -2738,7 +2760,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       do {
        ret = bl.read_fd(STDIN_FILENO, 1024); // from stdin
        if (ret < 0) {
-         goto out;
+         return 1;
         }
       } while (ret > 0);
     }
@@ -2750,14 +2772,15 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error setting omap value " << pool_name << "/" << oid << "/"
            << omap_key_pretty << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       ret = 0;
     }
   } else if (strcmp(nargs[0], "getomapval") == 0) {
     uint32_t min_args = (omap_key_valid ? 2 : 3);
     if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     string oid(nargs[1]);
@@ -2779,7 +2802,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error getting omap value " << pool_name << "/" << oid << "/"
           << omap_key_pretty << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       ret = 0;
     }
@@ -2797,13 +2820,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     } else {
       cout << "No such key: " << pool_name << "/" << oid << "/"
            << omap_key_pretty << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "rmomapkey") == 0) {
     uint32_t num_args = (omap_key_valid ? 2 : 3);
     if (!pool_name || nargs.size() != num_args) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     string oid(nargs[1]);
@@ -2818,13 +2841,14 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error removing omap key " << pool_name << "/" << oid << "/"
           << omap_key_pretty << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     } else {
       ret = 0;
     }
   } else if (strcmp(nargs[0], "clearomap") == 0) {
     if (!pool_name || nargs.size() < 2) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     for (unsigned i=1; i < nargs.size(); i++){
@@ -2833,13 +2857,15 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error clearing omap keys " << pool_name << "/" << oid << "/"
              << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
     }
     ret = 0;
   } else if (strcmp(nargs[0], "listomapvals") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     string last_read = "";
@@ -2875,11 +2901,15 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = 0;
   }
   else if (strcmp(nargs[0], "cp") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
 
-    if (nargs.size() < 2 || nargs.size() > 3)
-      usage_exit();
+    if (nargs.size() < 2 || nargs.size() > 3) {
+      usage(cerr);
+      return 1;
+    }
 
     const char *target = target_pool_name;
     if (!target)
@@ -2889,8 +2919,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (nargs.size() < 3) {
       if (strcmp(target, pool_name) == 0) {
         cerr << "cannot copy object into itself" << std::endl;
-       ret = -1;
-       goto out;
+       return 1;
       }
       target_obj = nargs[1];
     } else {
@@ -2903,7 +2932,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error opening target pool " << target << ": "
            << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     if (target_oloc.size()) {
       target_ctx.locator_set_key(target_oloc);
@@ -2915,11 +2944,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = do_copy(io_ctx, nargs[1], target_ctx, target_obj);
     if (ret < 0) {
       cerr << "error copying " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "rm") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     vector<const char *>::iterator iter = nargs.begin();
     ++iter;
     for (; iter != nargs.end(); ++iter) {
@@ -2935,18 +2966,20 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
         string name = (nspace.size() ? nspace + "/" : "" ) + oid;
         cerr << "error removing " << pool_name << ">" << name << ": " << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
     }
   }
   else if (strcmp(nargs[0], "create") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     ret = io_ctx.create(oid, true);
     if (ret < 0) {
       cerr << "error creating " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   }
 
@@ -3077,15 +3110,16 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   }
   else if (strcmp(nargs[0], "cppool") == 0) {
     bool force = nargs.size() == 4 && !strcmp(nargs[3], "--yes-i-really-mean-it");
-    if (nargs.size() != 3 && !(nargs.size() == 4 && force))
-      usage_exit();
+    if (nargs.size() != 3 && !(nargs.size() == 4 && force)) {
+      usage(cerr);
+      return 1;
+    }
     const char *src_pool = nargs[1];
     const char *target_pool = nargs[2];
 
     if (strcmp(src_pool, target_pool) == 0) {
       cerr << "cannot copy pool into itself" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
 
     cerr << "WARNING: pool copy does not preserve user_version, which some "
@@ -3107,7 +3141,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error copying pool " << src_pool << " => " << target_pool << ": "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     cout << "successfully copied pool " << nargs[1] << std::endl;
   }
@@ -3136,21 +3170,22 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "purge") == 0) {
-    if (nargs.size() < 2)
-      usage_exit();
+    if (nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     if (nargs.size() < 3 ||
        strcmp(nargs[2], "--yes-i-really-really-mean-it") != 0) {
       cerr << "WARNING:\n"
           << "  This will PERMANENTLY DESTROY all objects from a pool with no way back.\n"
           << "  To confirm, follow pool with --yes-i-really-really-mean-it" << std::endl;
-      ret = -1;
-      goto out;
+      return 1;
     }
     ret = rados.ioctx_create(nargs[1], io_ctx);
     if (ret < 0) {
       cerr << "error pool " << nargs[1] << ": "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     io_ctx.set_namespace(all_nspaces);
     io_ctx.set_osdmap_full_try();
@@ -3165,8 +3200,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "lssnap") == 0) {
-    if (!pool_name || nargs.size() != 1)
-      usage_exit();
+    if (!pool_name || nargs.size() != 1) {
+      usage(cerr);
+      return 1;
+    }
 
     vector<snap_t> snaps;
     io_ctx.snap_list(&snaps);
@@ -3200,53 +3237,60 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   }
 
   else if (strcmp(nargs[0], "mksnap") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     ret = io_ctx.snap_create(nargs[1]);
     if (ret < 0) {
       cerr << "error creating pool " << pool_name << " snapshot " << nargs[1]
           << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     cout << "created pool " << pool_name << " snap " << nargs[1] << std::endl;
   }
 
   else if (strcmp(nargs[0], "rmsnap") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     ret = io_ctx.snap_remove(nargs[1]);
     if (ret < 0) {
       cerr << "error removing pool " << pool_name << " snapshot " << nargs[1]
           << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     cout << "removed pool " << pool_name << " snap " << nargs[1] << std::endl;
   }
 
   else if (strcmp(nargs[0], "rollback") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
 
     ret = io_ctx.snap_rollback(nargs[1], nargs[2]);
     if (ret < 0) {
       cerr << "error rolling back pool " << pool_name << " to snapshot " << nargs[1]
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     cout << "rolled back pool " << pool_name
         << " to snapshot " << nargs[2] << std::endl;
   }
   else if (strcmp(nargs[0], "bench") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
     char* endptr = NULL;
     int seconds = strtol(nargs[1], &endptr, 10);
     if (*endptr) {
       cerr << "Invalid value for seconds: '" << nargs[1] << "'" << std::endl;
-      ret = -EINVAL;
-      goto out;
+      return 1;
     }
     int operation = 0;
     if (strcmp(nargs[2], "write") == 0)
@@ -3255,21 +3299,21 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       operation = OP_SEQ_READ;
     else if (strcmp(nargs[2], "rand") == 0)
       operation = OP_RAND_READ;
-    else
-      usage_exit();
+    else {
+      usage(cerr);
+      return 1;
+    }
     if (operation != OP_WRITE) {
       if (block_size_specified) {
         cerr << "-b|--block_size option can be used only with 'write' bench test"
              << std::endl;
-        ret = -EINVAL;
-        goto out;
+        return 1;
       }
       if (bench_write_dest != 0) {
         cerr << "--write-object, --write-omap and --write-xattr options can "
                 "only be used with the 'write' bench test"
              << std::endl;
-        ret = -EINVAL;
-        goto out;
+        return 1;
       }
     }
     else if (bench_write_dest == 0) {
@@ -3279,8 +3323,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (!formatter && output) {
       cerr << "-o|--output option can only be used with '--format' option"
            << std::endl;
-      ret = -EINVAL;
-      goto out;
+      return 1;
     }
     RadosBencher bencher(g_ceph_context, rados, io_ctx);
     bencher.set_show_time(show_time);
@@ -3309,8 +3352,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       delete outstream;
   }
   else if (strcmp(nargs[0], "cleanup") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
     if (wildcard)
       io_ctx.set_namespace(all_nspaces);
     RadosBencher bencher(g_ceph_context, rados, io_ctx);
@@ -3319,8 +3364,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cerr << "error during cleanup: " << cpp_strerror(ret) << std::endl;
   }
   else if (strcmp(nargs[0], "watch") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     RadosWatchCtx ctx(io_ctx, oid.c_str());
     uint64_t cookie;
@@ -3335,8 +3382,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     }
   }
   else if (strcmp(nargs[0], "notify") == 0) {
-    if (!pool_name || nargs.size() < 3)
-      usage_exit();
+    if (!pool_name || nargs.size() < 3) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     string msg(nargs[2]);
     bufferlist bl, replybl;
@@ -3366,30 +3415,35 @@ 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)
-      usage_exit();
+    if (!pool_name || nargs.size() < 4) {
+      usage(cerr);
+      return 1;
+    }
     string err;
     string oid(nargs[1]);
     uint64_t expected_object_size = strict_strtoll(nargs[2], 10, &err);
     if (!err.empty()) {
       cerr << "couldn't parse expected_object_size: " << err << std::endl;
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
     uint64_t expected_write_size = strict_strtoll(nargs[3], 10, &err);
     if (!err.empty()) {
       cerr << "couldn't parse expected_write_size: " << err << std::endl;
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
     ret = io_ctx.set_alloc_hint(oid, expected_object_size, expected_write_size);
     if (ret < 0) {
       cerr << "error setting alloc-hint " << pool_name << "/" << oid << ": "
            << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "load-gen") == 0) {
     if (!pool_name) {
       cerr << "error: must specify pool" << std::endl;
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
     LoadGen lg(&rados);
     if (min_obj_len)
@@ -3418,21 +3472,23 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = lg.bootstrap(pool_name);
     if (ret < 0) {
       cerr << "load-gen bootstrap failed" << std::endl;
-      exit(1);
+      return 1;
     }
     cout << "load-gen will run " << lg.run_length << " seconds" << std::endl;
     lg.run();
     lg.cleanup();
   } else if (strcmp(nargs[0], "listomapkeys") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     set<string> out_keys;
     ret = io_ctx.omap_get_keys(nargs[1], "", LONG_MAX, &out_keys);
     if (ret < 0) {
       cerr << "error getting omap key set " << pool_name << "/"
           << nargs[1] << ": "  << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
 
     for (set<string>::iterator iter = out_keys.begin();
@@ -3440,16 +3496,20 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cout << *iter << std::endl;
     }
   } else if (strcmp(nargs[0], "lock") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
 
     if (!formatter) {
       formatter = new JSONFormatter(pretty_format);
     }
     ret = do_lock_cmd(nargs, opts, &io_ctx, formatter);
   } else if (strcmp(nargs[0], "listwatchers") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     std::list<obj_watch_t> lw;
@@ -3457,7 +3517,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = io_ctx.list_watchers(oid, &lw);
     if (ret < 0) {
       cerr << "error listing watchers " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     else
       ret = 0;
@@ -3466,8 +3526,10 @@ 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)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
 
     string oid(nargs[1]);
     snap_set_t ls;
@@ -3476,7 +3538,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = io_ctx.list_snaps(oid, &ls);
     if (ret < 0) {
       cerr << "error listing snap shots " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
     else
       ret = 0;
@@ -3605,8 +3667,10 @@ 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)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     if (with_clones) {
       snap_set_t ls;
@@ -3615,7 +3679,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error listing snapshots " << pool_name << "/" << oid << ": "
              << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
       for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
            ci != ls.clones.end(); ++ci) {
@@ -3626,7 +3690,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (ret < 0) {
           cerr << "error from cache-flush " << oid << ": "
                << cpp_strerror(ret) << std::endl;
-          goto out;
+          return 1;
         }
       }
     } else {
@@ -3634,12 +3698,14 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error from cache-flush " << oid << ": "
             << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
     }
   } else if (strcmp(nargs[0], "cache-try-flush") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     if (with_clones) {
       snap_set_t ls;
@@ -3648,7 +3714,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error listing snapshots " << pool_name << "/" << oid << ": "
              << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
       for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
            ci != ls.clones.end(); ++ci) {
@@ -3659,7 +3725,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (ret < 0) {
           cerr << "error from cache-flush " << oid << ": "
                << cpp_strerror(ret) << std::endl;
-          goto out;
+          return 1;
         }
       }
     } else {
@@ -3667,12 +3733,14 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error from cache-flush " << oid << ": "
              << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
     }
   } else if (strcmp(nargs[0], "cache-evict") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
     if (with_clones) {
       snap_set_t ls;
@@ -3681,7 +3749,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error listing snapshots " << pool_name << "/" << oid << ": "
              << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
       for (std::vector<clone_info_t>::iterator ci = ls.clones.begin();
            ci != ls.clones.end(); ++ci) {
@@ -3692,7 +3760,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         if (ret < 0) {
           cerr << "error from cache-flush " << oid << ": "
                << cpp_strerror(ret) << std::endl;
-          goto out;
+          return 1;
         }
       }
     } else {
@@ -3700,30 +3768,36 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (ret < 0) {
         cerr << "error from cache-flush " << oid << ": "
              << cpp_strerror(ret) << std::endl;
-        goto out;
+        return 1;
       }
     }
   } else if (strcmp(nargs[0], "cache-flush-evict-all") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
     ret = do_cache_flush_evict_all(io_ctx, true);
     if (ret < 0) {
       cerr << "error from cache-flush-evict-all: "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "cache-try-flush-evict-all") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
     ret = do_cache_flush_evict_all(io_ctx, false);
     if (ret < 0) {
       cerr << "error from cache-try-flush-evict-all: "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "set-redirect") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
 
     const char *target = target_pool_name;
     if (!target)
@@ -3733,8 +3807,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (nargs.size() < 3) {
       if (strcmp(target, pool_name) == 0) {
         cerr << "cannot copy object into itself" << std::endl;
-       ret = -1;
-       goto out;
+           return 1;
       }
       target_obj = nargs[1];
     } else {
@@ -3759,11 +3832,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ret = io_ctx.operate(nargs[1], &op);
     if (ret < 0) {
       cerr << "error set-redirect " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "set-chunk") == 0) {
-    if (!pool_name)
-      usage_exit();
+    if (!pool_name) {
+      usage(cerr);
+      return 1;
+    }
 
     const char *target = target_pool_name;
     if (!target)
@@ -3774,27 +3849,25 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     uint64_t tgt_offset;
     string tgt_oid;
     if (nargs.size() < 6) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     } else {
       char* endptr = NULL;
       offset = strtoull(nargs[2], &endptr, 10);
       if (*endptr) {
        cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
-       ret = -EINVAL;
-       goto out;
+       return 1;
       }
       length = strtoull(nargs[3], &endptr, 10);
       if (*endptr) {
        cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
-       ret = -EINVAL;
-       goto out;
+       return 1;
       }
       tgt_oid = string(nargs[4]);
       tgt_offset = strtoull(nargs[5], &endptr, 10);
       if (*endptr) {
        cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl;
-       ret = -EINVAL;
-       goto out;
+       return 1;
       }
     }
 
@@ -3811,11 +3884,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cerr << "error set-chunk " << pool_name << "/" << nargs[1] << " " << " offset " << offset
            << " length " << length << " target_pool " << target 
            << "tgt_offset: " << tgt_offset << " : " << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "tier-promote") == 0) {
-    if (!pool_name || nargs.size() < 2)
-      usage_exit();
+    if (!pool_name || nargs.size() < 2) {
+      usage(cerr);
+      return 1;
+    }
     string oid(nargs[1]);
 
     ObjectWriteOperation op;
@@ -3824,12 +3899,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error tier-promote " << pool_name << "/" << oid << " : " 
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "export") == 0) {
     // export [filename]
     if (!pool_name || nargs.size() > 2) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     int file_fd;
@@ -3840,8 +3916,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (file_fd < 0) {
         cerr << "Error opening '" << nargs[1] << "': "
           << cpp_strerror(file_fd) << std::endl;
-        ret = file_fd;
-        goto out;
+        return 1;
       }
     }
 
@@ -3854,12 +3929,13 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error from export: "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else if (strcmp(nargs[0], "import") == 0) {
     // import [--no-overwrite] [--dry-run] <filename | - >
     if (!pool_name || nargs.size() > 4 || nargs.size() < 2) {
-      usage_exit();
+      usage(cerr);
+      return 1;
     }
 
     // Last arg is the filename
@@ -3877,8 +3953,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
         dry_run = true;
       } else {
         std::cerr << "Invalid argument '" << arg << "'" << std::endl;
-        ret = -EINVAL;
-        goto out;
+        return 1;
       }
     }
 
@@ -3890,8 +3965,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (file_fd < 0) {
         cerr << "Error opening '" << filename << "': "
           << cpp_strerror(file_fd) << std::endl;
-        ret = file_fd;
-        goto out;
+        return 1;
       }
     }
 
@@ -3904,12 +3978,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     if (ret < 0) {
       cerr << "error from import: "
           << cpp_strerror(ret) << std::endl;
-      goto out;
+      return 1;
     }
   } else {
     cerr << "unrecognized command " << nargs[0] << "; -h or --help for usage" << std::endl;
     ret = -EINVAL;
-    goto out;
   }
 
   if (ret < 0)