]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/Lock.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / tools / rbd / action / Lock.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
10 #include <iostream>
11 #include <boost/program_options.hpp>
12
13 namespace rbd {
14 namespace action {
15 namespace lock {
16
17 namespace at = argument_types;
18 namespace po = boost::program_options;
19
20 namespace {
21
22 void add_id_option(po::options_description *positional) {
23 positional->add_options()
24 ("lock-id", "unique lock id");
25 }
26
27 int get_id(const po::variables_map &vm, std::string *id) {
28 *id = utils::get_positional_argument(vm, 1);
29 if (id->empty()) {
30 std::cerr << "rbd: lock id was not specified" << std::endl;
31 return -EINVAL;
32 }
33 return 0;
34 }
35
36 } // anonymous namespace
37
38 static int do_lock_list(librbd::Image& image, Formatter *f)
39 {
40 std::list<librbd::locker_t> lockers;
41 bool exclusive;
42 std::string tag;
43 TextTable tbl;
44 int r;
45
46 r = image.list_lockers(&lockers, &exclusive, &tag);
47 if (r < 0)
48 return r;
49
50 if (f) {
51 f->open_array_section("locks");
52 } else {
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);
56 }
57
58 if (lockers.size()) {
59 bool one = (lockers.size() == 1);
60
61 if (!f) {
62 std::cout << "There " << (one ? "is " : "are ") << lockers.size()
63 << (exclusive ? " exclusive" : " shared")
64 << " lock" << (one ? "" : "s") << " on this image.\n";
65 if (!exclusive)
66 std::cout << "Lock tag: " << tag << "\n";
67 }
68
69 for (std::list<librbd::locker_t>::const_iterator it = lockers.begin();
70 it != lockers.end(); ++it) {
71 if (f) {
72 f->open_object_section("lock");
73 f->dump_string("id", it->cookie);
74 f->dump_string("locker", it->client);
75 f->dump_string("address", it->address);
76 f->close_section();
77 } else {
78 tbl << it->client << it->cookie << it->address << TextTable::endrow;
79 }
80 }
81 if (!f)
82 std::cout << tbl;
83 }
84
85 if (f) {
86 f->close_section();
87 f->flush(std::cout);
88 }
89 return 0;
90 }
91
92 static int do_lock_add(librbd::Image& image, const char *cookie,
93 const char *tag)
94 {
95 if (tag)
96 return image.lock_shared(cookie, tag);
97 else
98 return image.lock_exclusive(cookie);
99 }
100
101 static int do_lock_remove(librbd::Image& image, const char *client,
102 const char *cookie)
103 {
104 return image.break_lock(client, cookie);
105 }
106
107 void get_list_arguments(po::options_description *positional,
108 po::options_description *options) {
109 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
110 at::add_format_options(options);
111 }
112
113 int execute_list(const po::variables_map &vm,
114 const std::vector<std::string> &ceph_global_init_args) {
115 size_t arg_index = 0;
116 std::string pool_name;
117 std::string namespace_name;
118 std::string image_name;
119 std::string snap_name;
120 int r = utils::get_pool_image_snapshot_names(
121 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
122 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
123 utils::SPEC_VALIDATION_NONE);
124 if (r < 0) {
125 return r;
126 }
127
128 at::Format::Formatter formatter;
129 r = utils::get_formatter(vm, &formatter);
130 if (r < 0) {
131 return r;
132 }
133
134 librados::Rados rados;
135 librados::IoCtx io_ctx;
136 librbd::Image image;
137 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
138 true, &rados, &io_ctx, &image);
139 if (r < 0) {
140 return r;
141 }
142
143 r = do_lock_list(image, formatter.get());
144 if (r < 0) {
145 std::cerr << "rbd: listing locks failed: " << cpp_strerror(r) << std::endl;
146 return r;
147 }
148 return 0;
149 }
150
151 void get_add_arguments(po::options_description *positional,
152 po::options_description *options) {
153 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
154 add_id_option(positional);
155 options->add_options()
156 ("shared", po::value<std::string>(), "shared lock tag");
157 }
158
159 int execute_add(const po::variables_map &vm,
160 const std::vector<std::string> &ceph_global_init_args) {
161 size_t arg_index = 0;
162 std::string pool_name;
163 std::string namespace_name;
164 std::string image_name;
165 std::string snap_name;
166 int r = utils::get_pool_image_snapshot_names(
167 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
168 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
169 utils::SPEC_VALIDATION_NONE);
170 if (r < 0) {
171 return r;
172 }
173
174 std::string lock_cookie;
175 r = get_id(vm, &lock_cookie);
176 if (r < 0) {
177 return r;
178 }
179
180 std::string lock_tag;
181 if (vm.count("shared")) {
182 lock_tag = vm["shared"].as<std::string>();
183 }
184
185 librados::Rados rados;
186 librados::IoCtx io_ctx;
187 librbd::Image image;
188 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
189 false, &rados, &io_ctx, &image);
190 if (r < 0) {
191 return r;
192 }
193
194 r = do_lock_add(image, lock_cookie.c_str(),
195 lock_tag.empty() ? nullptr : lock_tag.c_str());
196 if (r < 0) {
197 if (r == -EBUSY || r == -EEXIST) {
198 if (!lock_tag.empty()) {
199 std::cerr << "rbd: lock is already held by someone else"
200 << " with a different tag" << std::endl;
201 } else {
202 std::cerr << "rbd: lock is already held by someone else" << std::endl;
203 }
204 } else {
205 std::cerr << "rbd: taking lock failed: " << cpp_strerror(r) << std::endl;
206 }
207 return r;
208 }
209 return 0;
210 }
211
212 void get_remove_arguments(po::options_description *positional,
213 po::options_description *options) {
214 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
215 add_id_option(positional);
216 positional->add_options()
217 ("locker", "locker client");
218 }
219
220 int execute_remove(const po::variables_map &vm,
221 const std::vector<std::string> &ceph_global_init_args) {
222 size_t arg_index = 0;
223 std::string pool_name;
224 std::string namespace_name;
225 std::string image_name;
226 std::string snap_name;
227 int r = utils::get_pool_image_snapshot_names(
228 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
229 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
230 utils::SPEC_VALIDATION_NONE);
231 if (r < 0) {
232 return r;
233 }
234
235 std::string lock_cookie;
236 r = get_id(vm, &lock_cookie);
237 if (r < 0) {
238 return r;
239 }
240
241 std::string lock_client = utils::get_positional_argument(vm, 2);
242 if (lock_client.empty()) {
243 std::cerr << "rbd: locker was not specified" << std::endl;
244 return -EINVAL;
245 }
246
247 librados::Rados rados;
248 librados::IoCtx io_ctx;
249 librbd::Image image;
250 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
251 false, &rados, &io_ctx, &image);
252 if (r < 0) {
253 return r;
254 }
255
256 r = do_lock_remove(image, lock_client.c_str(), lock_cookie.c_str());
257 if (r < 0) {
258 std::cerr << "rbd: releasing lock failed: " << cpp_strerror(r) << std::endl;
259 return r;
260 }
261 return 0;
262 }
263
264 Shell::Action action_list(
265 {"lock", "list"}, {"lock", "ls"}, "Show locks held on an image.", "",
266 &get_list_arguments, &execute_list);
267 Shell::Action action_add(
268 {"lock", "add"}, {}, "Take a lock on an image.", "",
269 &get_add_arguments, &execute_add);
270 Shell::Action action_remove(
271 {"lock", "remove"}, {"lock", "rm"}, "Release a lock on an image.", "",
272 &get_remove_arguments, &execute_remove);
273
274 } // namespace lock
275 } // namespace action
276 } // namespace rbd