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