1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Shell.h"
6 #include "tools/rbd/Utils.h"
7 #include "common/errno.h"
8 #include "common/Formatter.h"
9 #include "common/TextTable.h"
11 #include <boost/program_options.hpp>
17 namespace at = argument_types;
18 namespace po = boost::program_options;
22 void add_id_option(po::options_description *positional) {
23 positional->add_options()
24 ("lock-id", "unique lock id");
27 int get_id(const po::variables_map &vm, std::string *id) {
28 *id = utils::get_positional_argument(vm, 1);
30 std::cerr << "rbd: lock id was not specified" << std::endl;
36 } // anonymous namespace
38 static int do_lock_list(librbd::Image& image, Formatter *f)
40 std::list<librbd::locker_t> lockers;
46 r = image.list_lockers(&lockers, &exclusive, &tag);
51 f->open_object_section("locks");
53 tbl.define_column("Locker", TextTable::LEFT, TextTable::LEFT);
54 tbl.define_column("ID", TextTable::LEFT, TextTable::LEFT);
55 tbl.define_column("Address", TextTable::LEFT, TextTable::LEFT);
59 bool one = (lockers.size() == 1);
62 std::cout << "There " << (one ? "is " : "are ") << lockers.size()
63 << (exclusive ? " exclusive" : " shared")
64 << " lock" << (one ? "" : "s") << " on this image.\n";
66 std::cout << "Lock tag: " << tag << "\n";
69 for (std::list<librbd::locker_t>::const_iterator it = lockers.begin();
70 it != lockers.end(); ++it) {
72 f->open_object_section(it->cookie.c_str());
73 f->dump_string("locker", it->client);
74 f->dump_string("address", it->address);
77 tbl << it->client << it->cookie << it->address << TextTable::endrow;
91 static int do_lock_add(librbd::Image& image, const char *cookie,
95 return image.lock_shared(cookie, tag);
97 return image.lock_exclusive(cookie);
100 static int do_lock_remove(librbd::Image& image, const char *client,
103 return image.break_lock(client, cookie);
106 void get_list_arguments(po::options_description *positional,
107 po::options_description *options) {
108 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
109 at::add_format_options(options);
112 int execute_list(const po::variables_map &vm) {
113 size_t arg_index = 0;
114 std::string pool_name;
115 std::string image_name;
116 std::string snap_name;
117 int r = utils::get_pool_image_snapshot_names(
118 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
119 &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
124 at::Format::Formatter formatter;
125 r = utils::get_formatter(vm, &formatter);
130 librados::Rados rados;
131 librados::IoCtx io_ctx;
133 r = utils::init_and_open_image(pool_name, image_name, "", "", true,
134 &rados, &io_ctx, &image);
139 r = do_lock_list(image, formatter.get());
141 std::cerr << "rbd: listing locks failed: " << cpp_strerror(r) << std::endl;
147 void get_add_arguments(po::options_description *positional,
148 po::options_description *options) {
149 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
150 add_id_option(positional);
151 options->add_options()
152 ("shared", po::value<std::string>(), "shared lock tag");
155 int execute_add(const po::variables_map &vm) {
156 size_t arg_index = 0;
157 std::string pool_name;
158 std::string image_name;
159 std::string snap_name;
160 int r = utils::get_pool_image_snapshot_names(
161 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
162 &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
167 std::string lock_cookie;
168 r = get_id(vm, &lock_cookie);
173 std::string lock_tag;
174 if (vm.count("shared")) {
175 lock_tag = vm["shared"].as<std::string>();
178 librados::Rados rados;
179 librados::IoCtx io_ctx;
181 r = utils::init_and_open_image(pool_name, image_name, "", "", false,
182 &rados, &io_ctx, &image);
187 r = do_lock_add(image, lock_cookie.c_str(),
188 lock_tag.empty() ? nullptr : lock_tag.c_str());
190 if (r == -EBUSY || r == -EEXIST) {
191 if (!lock_tag.empty()) {
192 std::cerr << "rbd: lock is already held by someone else"
193 << " with a different tag" << std::endl;
195 std::cerr << "rbd: lock is already held by someone else" << std::endl;
198 std::cerr << "rbd: taking lock failed: " << cpp_strerror(r) << std::endl;
205 void get_remove_arguments(po::options_description *positional,
206 po::options_description *options) {
207 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
208 add_id_option(positional);
209 positional->add_options()
210 ("locker", "locker client");
213 int execute_remove(const po::variables_map &vm) {
214 size_t arg_index = 0;
215 std::string pool_name;
216 std::string image_name;
217 std::string snap_name;
218 int r = utils::get_pool_image_snapshot_names(
219 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
220 &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
225 std::string lock_cookie;
226 r = get_id(vm, &lock_cookie);
231 std::string lock_client = utils::get_positional_argument(vm, 2);
232 if (lock_client.empty()) {
233 std::cerr << "rbd: locker was not specified" << std::endl;
237 librados::Rados rados;
238 librados::IoCtx io_ctx;
240 r = utils::init_and_open_image(pool_name, image_name, "", "", false,
241 &rados, &io_ctx, &image);
246 r = do_lock_remove(image, lock_client.c_str(), lock_cookie.c_str());
248 std::cerr << "rbd: releasing lock failed: " << cpp_strerror(r) << std::endl;
254 Shell::Action action_list(
255 {"lock", "list"}, {"lock", "ls"}, "Show locks held on an image.", "",
256 &get_list_arguments, &execute_list);
257 Shell::Action action_add(
258 {"lock", "add"}, {}, "Take a lock on an image.", "",
259 &get_add_arguments, &execute_add);
260 Shell::Action action_remove(
261 {"lock", "remove"}, {"lock", "rm"}, "Release a lock on an image.", "",
262 &get_remove_arguments, &execute_remove);
265 } // namespace action