]>
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 | /** \file | |
5 | * | |
6 | * This is an OSD class that implements methods for object | |
7 | * advisory locking. | |
8 | * | |
9 | */ | |
10 | ||
7c673cae | 11 | #include <errno.h> |
7c673cae | 12 | #include <map> |
11fdf7f2 | 13 | #include <sstream> |
7c673cae FG |
14 | |
15 | #include "include/types.h" | |
16 | #include "include/utime.h" | |
17 | #include "objclass/objclass.h" | |
18 | ||
19 | #include "common/errno.h" | |
20 | #include "common/Clock.h" | |
21 | ||
22 | #include "cls/lock/cls_lock_types.h" | |
23 | #include "cls/lock/cls_lock_ops.h" | |
24 | ||
25 | #include "global/global_context.h" | |
26 | ||
27 | #include "include/compat.h" | |
28 | ||
29 | ||
30 | using namespace rados::cls::lock; | |
31 | ||
32 | ||
33 | CLS_VER(1,0) | |
34 | CLS_NAME(lock) | |
35 | ||
36 | #define LOCK_PREFIX "lock." | |
37 | ||
f64942e4 AA |
38 | static int clean_lock(cls_method_context_t hctx) |
39 | { | |
40 | int r = cls_cxx_remove(hctx); | |
41 | if (r < 0) | |
42 | return r; | |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
47 | static int read_lock(cls_method_context_t hctx, | |
48 | const string& name, | |
49 | lock_info_t *lock) | |
7c673cae FG |
50 | { |
51 | bufferlist bl; | |
52 | string key = LOCK_PREFIX; | |
53 | key.append(name); | |
54 | ||
55 | int r = cls_cxx_getxattr(hctx, key.c_str(), &bl); | |
56 | if (r < 0) { | |
57 | if (r == -ENODATA) { | |
58 | *lock = lock_info_t(); | |
59 | return 0; | |
60 | } | |
61 | if (r != -ENOENT) { | |
62 | CLS_ERR("error reading xattr %s: %d", key.c_str(), r); | |
63 | } | |
64 | return r; | |
65 | } | |
66 | ||
67 | try { | |
11fdf7f2 TL |
68 | auto it = bl.cbegin(); |
69 | decode(*lock, it); | |
7c673cae FG |
70 | } catch (const buffer::error &err) { |
71 | CLS_ERR("error decoding %s", key.c_str()); | |
72 | return -EIO; | |
73 | } | |
74 | ||
75 | /* now trim expired locks */ | |
76 | ||
77 | utime_t now = ceph_clock_now(); | |
78 | ||
79 | map<locker_id_t, locker_info_t>::iterator iter = lock->lockers.begin(); | |
80 | ||
81 | while (iter != lock->lockers.end()) { | |
7c673cae FG |
82 | struct locker_info_t& info = iter->second; |
83 | if (!info.expiration.is_zero() && info.expiration < now) { | |
84 | CLS_LOG(20, "expiring locker"); | |
f64942e4 AA |
85 | iter = lock->lockers.erase(iter); |
86 | } else { | |
87 | ++iter; | |
7c673cae | 88 | } |
f64942e4 | 89 | } |
7c673cae | 90 | |
f64942e4 AA |
91 | if (lock->lockers.empty() && cls_lock_is_ephemeral(lock->lock_type)) { |
92 | r = clean_lock(hctx); | |
93 | if (r < 0) { | |
94 | CLS_ERR("error, on read, cleaning lock object %s", cpp_strerror(r).c_str()); | |
95 | } | |
7c673cae FG |
96 | } |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | static int write_lock(cls_method_context_t hctx, const string& name, const lock_info_t& lock) | |
102 | { | |
11fdf7f2 | 103 | using ceph::encode; |
7c673cae FG |
104 | string key = LOCK_PREFIX; |
105 | key.append(name); | |
106 | ||
107 | bufferlist lock_bl; | |
11fdf7f2 | 108 | encode(lock, lock_bl, cls_get_client_features(hctx)); |
7c673cae FG |
109 | |
110 | int r = cls_cxx_setxattr(hctx, key.c_str(), &lock_bl); | |
111 | if (r < 0) | |
112 | return r; | |
113 | ||
114 | return 0; | |
115 | } | |
116 | ||
117 | /** | |
118 | * helper function to add a lock and update disk state. | |
119 | * | |
120 | * Input: | |
121 | * @param name Lock name | |
122 | * @param lock_type Type of lock (exclusive / shared) | |
123 | * @param duration Duration of lock (in seconds). Zero means it doesn't expire. | |
124 | * @param flags lock flags | |
125 | * @param cookie The cookie to set in the lock | |
126 | * @param tag The tag to match with the lock (can only lock with matching tags) | |
127 | * @param lock_description The lock description to set (if not empty) | |
128 | * @param locker_description The locker description | |
129 | * | |
130 | * @return 0 on success, or -errno on failure | |
131 | */ | |
132 | static int lock_obj(cls_method_context_t hctx, | |
133 | const string& name, | |
134 | ClsLockType lock_type, | |
135 | utime_t duration, | |
136 | const string& description, | |
137 | uint8_t flags, | |
138 | const string& cookie, | |
139 | const string& tag) | |
140 | { | |
f64942e4 | 141 | bool exclusive = cls_lock_is_exclusive(lock_type); |
7c673cae | 142 | lock_info_t linfo; |
f64942e4 AA |
143 | bool fail_if_exists = (flags & LOCK_FLAG_MAY_RENEW) == 0; |
144 | bool fail_if_does_not_exist = flags & LOCK_FLAG_MUST_RENEW; | |
7c673cae | 145 | |
f64942e4 AA |
146 | CLS_LOG(20, |
147 | "requested lock_type=%s fail_if_exists=%d fail_if_does_not_exist=%d", | |
148 | cls_lock_type_str(lock_type), fail_if_exists, fail_if_does_not_exist); | |
149 | if (!cls_lock_is_valid(lock_type)) { | |
7c673cae | 150 | return -EINVAL; |
f64942e4 | 151 | } |
7c673cae FG |
152 | |
153 | if (name.empty()) | |
154 | return -EINVAL; | |
155 | ||
f64942e4 AA |
156 | if (!fail_if_exists && fail_if_does_not_exist) { |
157 | // at most one of LOCK_FLAG_MAY_RENEW and LOCK_FLAG_MUST_RENEW may | |
158 | // be set since they have different implications if the lock does | |
159 | // not already exist | |
160 | return -EINVAL; | |
161 | } | |
162 | ||
7c673cae FG |
163 | // see if there's already a locker |
164 | int r = read_lock(hctx, name, &linfo); | |
165 | if (r < 0 && r != -ENOENT) { | |
166 | CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); | |
167 | return r; | |
168 | } | |
f64942e4 | 169 | |
7c673cae FG |
170 | map<locker_id_t, locker_info_t>& lockers = linfo.lockers; |
171 | map<locker_id_t, locker_info_t>::iterator iter; | |
172 | ||
173 | locker_id_t id; | |
174 | id.cookie = cookie; | |
175 | entity_inst_t inst; | |
176 | r = cls_get_request_origin(hctx, &inst); | |
177 | id.locker = inst.name; | |
11fdf7f2 | 178 | ceph_assert(r == 0); |
7c673cae FG |
179 | |
180 | /* check this early, before we check fail_if_exists, otherwise we might | |
181 | * remove the locker entry and not check it later */ | |
182 | if (lockers.size() && tag != linfo.tag) { | |
183 | CLS_LOG(20, "cannot take lock on object, conflicting tag"); | |
184 | return -EBUSY; | |
185 | } | |
186 | ||
187 | ClsLockType existing_lock_type = linfo.lock_type; | |
188 | CLS_LOG(20, "existing_lock_type=%s", cls_lock_type_str(existing_lock_type)); | |
189 | iter = lockers.find(id); | |
190 | if (iter != lockers.end()) { | |
f64942e4 | 191 | if (fail_if_exists && !fail_if_does_not_exist) { |
7c673cae FG |
192 | return -EEXIST; |
193 | } else { | |
194 | lockers.erase(iter); // remove old entry | |
195 | } | |
f64942e4 AA |
196 | } else if (fail_if_does_not_exist) { |
197 | return -ENOENT; | |
7c673cae FG |
198 | } |
199 | ||
200 | if (!lockers.empty()) { | |
201 | if (exclusive) { | |
81eedcae TL |
202 | auto locker_lister = |
203 | [&lockers]() -> std::string { | |
204 | std::stringstream locker_list; | |
205 | locker_list << lockers; | |
206 | return locker_list.str(); | |
207 | }; | |
208 | CLS_LOG(20, "could not exclusive-lock object, already locked by %s", | |
209 | locker_lister().c_str()); | |
7c673cae FG |
210 | return -EBUSY; |
211 | } | |
212 | ||
213 | if (existing_lock_type != lock_type) { | |
214 | CLS_LOG(20, "cannot take lock on object, conflicting lock type"); | |
215 | return -EBUSY; | |
216 | } | |
217 | } | |
218 | ||
219 | linfo.lock_type = lock_type; | |
220 | linfo.tag = tag; | |
221 | utime_t expiration; | |
222 | if (!duration.is_zero()) { | |
223 | expiration = ceph_clock_now(); | |
224 | expiration += duration; | |
225 | ||
226 | } | |
11fdf7f2 TL |
227 | // make all addrs of type legacy, because v2 clients speak v2 or v1, |
228 | // even depending on which OSD they are talking to, and the type | |
229 | // isn't what uniquely identifies them. also, storing a v1 addr | |
230 | // here means that old clients who get this locker_info won't see an | |
231 | // old "msgr2:" prefix. | |
232 | inst.addr.set_type(entity_addr_t::TYPE_LEGACY); | |
233 | ||
7c673cae FG |
234 | struct locker_info_t info(expiration, inst.addr, description); |
235 | ||
236 | linfo.lockers[id] = info; | |
237 | ||
238 | r = write_lock(hctx, name, linfo); | |
239 | if (r < 0) | |
240 | return r; | |
241 | ||
242 | return 0; | |
243 | } | |
244 | ||
245 | /** | |
246 | * Set an exclusive lock on an object for the activating client, if possible. | |
247 | * | |
248 | * Input: | |
249 | * @param cls_lock_lock_op request input | |
250 | * | |
251 | * @returns 0 on success, -EINVAL if it can't decode the lock_cookie, | |
252 | * -EBUSY if the object is already locked, or -errno on (unexpected) failure. | |
253 | */ | |
254 | static int lock_op(cls_method_context_t hctx, | |
255 | bufferlist *in, bufferlist *out) | |
256 | { | |
257 | CLS_LOG(20, "lock_op"); | |
258 | cls_lock_lock_op op; | |
259 | try { | |
11fdf7f2 TL |
260 | auto iter = in->cbegin(); |
261 | decode(op, iter); | |
7c673cae FG |
262 | } catch (const buffer::error &err) { |
263 | return -EINVAL; | |
264 | } | |
265 | ||
266 | return lock_obj(hctx, | |
267 | op.name, op.type, op.duration, op.description, | |
268 | op.flags, op.cookie, op.tag); | |
269 | } | |
270 | ||
271 | /** | |
272 | * helper function to remove a lock from on disk and clean up state. | |
273 | * | |
274 | * @param name The lock name | |
275 | * @param locker The locker entity name | |
276 | * @param cookie The user-defined cookie associated with the lock. | |
277 | * | |
278 | * @return 0 on success, -ENOENT if there is no such lock (either | |
279 | * entity or cookie is wrong), or -errno on other error. | |
280 | */ | |
281 | static int remove_lock(cls_method_context_t hctx, | |
f64942e4 AA |
282 | const string& name, |
283 | entity_name_t& locker, | |
284 | const string& cookie) | |
7c673cae FG |
285 | { |
286 | // get current lockers | |
287 | lock_info_t linfo; | |
288 | int r = read_lock(hctx, name, &linfo); | |
289 | if (r < 0) { | |
290 | CLS_ERR("Could not read list of current lockers off disk: %s", cpp_strerror(r).c_str()); | |
291 | return r; | |
292 | } | |
293 | ||
294 | map<locker_id_t, locker_info_t>& lockers = linfo.lockers; | |
295 | struct locker_id_t id(locker, cookie); | |
296 | ||
297 | // remove named locker from set | |
298 | map<locker_id_t, locker_info_t>::iterator iter = lockers.find(id); | |
299 | if (iter == lockers.end()) { // no such key | |
9f95a23c TL |
300 | CLS_LOG(10, "locker %s [name: %s.%ld, cookie: %s] does not exist", name.c_str(), |
301 | locker.type_str(), locker.num(), cookie.c_str()); | |
7c673cae FG |
302 | return -ENOENT; |
303 | } | |
304 | lockers.erase(iter); | |
305 | ||
f64942e4 AA |
306 | if (cls_lock_is_ephemeral(linfo.lock_type)) { |
307 | ceph_assert(lockers.empty()); | |
308 | r = clean_lock(hctx); | |
309 | } else { | |
310 | r = write_lock(hctx, name, linfo); | |
311 | } | |
7c673cae FG |
312 | |
313 | return r; | |
314 | } | |
315 | ||
316 | /** | |
317 | * Unlock an object which the activating client currently has locked. | |
318 | * | |
319 | * Input: | |
320 | * @param cls_lock_unlock_op request input | |
321 | * | |
322 | * @return 0 on success, -EINVAL if it can't decode the cookie, -ENOENT | |
323 | * if there is no such lock (either entity or cookie is wrong), or | |
324 | * -errno on other (unexpected) error. | |
325 | */ | |
326 | static int unlock_op(cls_method_context_t hctx, | |
327 | bufferlist *in, bufferlist *out) | |
328 | { | |
329 | CLS_LOG(20, "unlock_op"); | |
330 | cls_lock_unlock_op op; | |
331 | try { | |
11fdf7f2 TL |
332 | auto iter = in->cbegin(); |
333 | decode(op, iter); | |
7c673cae FG |
334 | } catch (const buffer::error& err) { |
335 | return -EINVAL; | |
336 | } | |
337 | ||
338 | entity_inst_t inst; | |
339 | int r = cls_get_request_origin(hctx, &inst); | |
11fdf7f2 | 340 | ceph_assert(r == 0); |
7c673cae FG |
341 | return remove_lock(hctx, op.name, inst.name, op.cookie); |
342 | } | |
343 | ||
344 | /** | |
345 | * Break the lock on an object held by any client. | |
346 | * | |
347 | * Input: | |
348 | * @param cls_lock_break_op request input | |
349 | * | |
350 | * @return 0 on success, -EINVAL if it can't decode the locker and | |
351 | * cookie, -ENOENT if there is no such lock (either entity or cookie | |
352 | * is wrong), or -errno on other (unexpected) error. | |
353 | */ | |
354 | static int break_lock(cls_method_context_t hctx, | |
f64942e4 | 355 | bufferlist *in, bufferlist *out) |
7c673cae FG |
356 | { |
357 | CLS_LOG(20, "break_lock"); | |
358 | cls_lock_break_op op; | |
359 | try { | |
11fdf7f2 TL |
360 | auto iter = in->cbegin(); |
361 | decode(op, iter); | |
7c673cae FG |
362 | } catch (const buffer::error& err) { |
363 | return -EINVAL; | |
364 | } | |
365 | ||
366 | return remove_lock(hctx, op.name, op.locker, op.cookie); | |
367 | } | |
368 | ||
369 | ||
370 | /** | |
371 | * Retrieve lock info: lockers, tag, exclusive | |
372 | * | |
373 | * Input: | |
374 | * @param cls_lock_list_lockers_op request input | |
375 | * | |
376 | * Output: | |
377 | * @param cls_lock_list_lockers_reply result | |
378 | * | |
379 | * @return 0 on success, -errno on failure. | |
380 | */ | |
381 | static int get_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out) | |
382 | { | |
383 | CLS_LOG(20, "get_info"); | |
384 | cls_lock_get_info_op op; | |
385 | try { | |
11fdf7f2 TL |
386 | auto iter = in->cbegin(); |
387 | decode(op, iter); | |
7c673cae FG |
388 | } catch (const buffer::error& err) { |
389 | return -EINVAL; | |
390 | } | |
391 | ||
392 | // get current lockers | |
393 | lock_info_t linfo; | |
394 | int r = read_lock(hctx, op.name, &linfo); | |
395 | if (r < 0) { | |
396 | CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); | |
397 | return r; | |
398 | } | |
399 | ||
400 | struct cls_lock_get_info_reply ret; | |
401 | ||
402 | map<locker_id_t, locker_info_t>::iterator iter; | |
403 | for (iter = linfo.lockers.begin(); iter != linfo.lockers.end(); ++iter) { | |
404 | ret.lockers[iter->first] = iter->second; | |
405 | } | |
406 | ret.lock_type = linfo.lock_type; | |
407 | ret.tag = linfo.tag; | |
408 | ||
11fdf7f2 | 409 | encode(ret, *out, cls_get_client_features(hctx)); |
7c673cae FG |
410 | |
411 | return 0; | |
412 | } | |
413 | ||
414 | ||
415 | /** | |
416 | * Retrieve a list of locks for this object | |
417 | * | |
418 | * Input: | |
419 | * @param in is ignored. | |
420 | * | |
421 | * Output: | |
422 | * @param out contains encoded cls_list_locks_reply | |
423 | * | |
424 | * @return 0 on success, -errno on failure. | |
425 | */ | |
426 | static int list_locks(cls_method_context_t hctx, bufferlist *in, bufferlist *out) | |
427 | { | |
428 | CLS_LOG(20, "list_locks"); | |
429 | ||
430 | map<string, bufferlist> attrs; | |
431 | ||
432 | int r = cls_cxx_getxattrs(hctx, &attrs); | |
433 | if (r < 0) | |
434 | return r; | |
435 | ||
436 | cls_lock_list_locks_reply ret; | |
437 | ||
438 | map<string, bufferlist>::iterator iter; | |
439 | size_t pos = sizeof(LOCK_PREFIX) - 1; | |
440 | for (iter = attrs.begin(); iter != attrs.end(); ++iter) { | |
441 | const string& attr = iter->first; | |
442 | if (attr.substr(0, pos).compare(LOCK_PREFIX) == 0) { | |
443 | ret.locks.push_back(attr.substr(pos)); | |
444 | } | |
445 | } | |
446 | ||
11fdf7f2 | 447 | encode(ret, *out); |
7c673cae FG |
448 | |
449 | return 0; | |
450 | } | |
451 | ||
452 | /** | |
453 | * Assert that the object is currently locked | |
454 | * | |
455 | * Input: | |
456 | * @param cls_lock_assert_op request input | |
457 | * | |
458 | * Output: | |
459 | * @param none | |
460 | * | |
461 | * @return 0 on success, -errno on failure. | |
462 | */ | |
463 | int assert_locked(cls_method_context_t hctx, bufferlist *in, bufferlist *out) | |
464 | { | |
465 | CLS_LOG(20, "assert_locked"); | |
466 | ||
467 | cls_lock_assert_op op; | |
468 | try { | |
11fdf7f2 TL |
469 | auto iter = in->cbegin(); |
470 | decode(op, iter); | |
7c673cae FG |
471 | } catch (const buffer::error& err) { |
472 | return -EINVAL; | |
473 | } | |
474 | ||
f64942e4 | 475 | if (!cls_lock_is_valid(op.type)) { |
7c673cae FG |
476 | return -EINVAL; |
477 | } | |
478 | ||
479 | if (op.name.empty()) { | |
480 | return -EINVAL; | |
481 | } | |
482 | ||
483 | // see if there's already a locker | |
484 | lock_info_t linfo; | |
485 | int r = read_lock(hctx, op.name, &linfo); | |
486 | if (r < 0) { | |
487 | CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); | |
488 | return r; | |
489 | } | |
490 | ||
491 | if (linfo.lockers.empty()) { | |
492 | CLS_LOG(20, "object not locked"); | |
493 | return -EBUSY; | |
494 | } | |
495 | ||
496 | if (linfo.lock_type != op.type) { | |
497 | CLS_LOG(20, "lock type mismatch: current=%s, assert=%s", | |
498 | cls_lock_type_str(linfo.lock_type), cls_lock_type_str(op.type)); | |
499 | return -EBUSY; | |
500 | } | |
501 | ||
502 | if (linfo.tag != op.tag) { | |
503 | CLS_LOG(20, "lock tag mismatch: current=%s, assert=%s", linfo.tag.c_str(), | |
504 | op.tag.c_str()); | |
505 | return -EBUSY; | |
506 | } | |
507 | ||
508 | entity_inst_t inst; | |
509 | r = cls_get_request_origin(hctx, &inst); | |
11fdf7f2 | 510 | ceph_assert(r == 0); |
7c673cae FG |
511 | |
512 | locker_id_t id; | |
513 | id.cookie = op.cookie; | |
514 | id.locker = inst.name; | |
515 | ||
516 | map<locker_id_t, locker_info_t>::iterator iter = linfo.lockers.find(id); | |
517 | if (iter == linfo.lockers.end()) { | |
518 | CLS_LOG(20, "not locked by assert client"); | |
519 | return -EBUSY; | |
520 | } | |
521 | return 0; | |
522 | } | |
523 | ||
524 | /** | |
525 | * Update the cookie associated with an object lock | |
526 | * | |
527 | * Input: | |
528 | * @param cls_lock_set_cookie_op request input | |
529 | * | |
530 | * Output: | |
531 | * @param none | |
532 | * | |
533 | * @return 0 on success, -errno on failure. | |
534 | */ | |
535 | int set_cookie(cls_method_context_t hctx, bufferlist *in, bufferlist *out) | |
536 | { | |
537 | CLS_LOG(20, "set_cookie"); | |
538 | ||
539 | cls_lock_set_cookie_op op; | |
540 | try { | |
11fdf7f2 TL |
541 | auto iter = in->cbegin(); |
542 | decode(op, iter); | |
7c673cae FG |
543 | } catch (const buffer::error& err) { |
544 | return -EINVAL; | |
545 | } | |
546 | ||
f64942e4 | 547 | if (!cls_lock_is_valid(op.type)) { |
7c673cae FG |
548 | return -EINVAL; |
549 | } | |
550 | ||
551 | if (op.name.empty()) { | |
552 | return -EINVAL; | |
553 | } | |
554 | ||
555 | // see if there's already a locker | |
556 | lock_info_t linfo; | |
557 | int r = read_lock(hctx, op.name, &linfo); | |
558 | if (r < 0) { | |
559 | CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); | |
560 | return r; | |
561 | } | |
562 | ||
563 | if (linfo.lockers.empty()) { | |
564 | CLS_LOG(20, "object not locked"); | |
565 | return -EBUSY; | |
566 | } | |
567 | ||
568 | if (linfo.lock_type != op.type) { | |
569 | CLS_LOG(20, "lock type mismatch: current=%s, assert=%s", | |
570 | cls_lock_type_str(linfo.lock_type), cls_lock_type_str(op.type)); | |
571 | return -EBUSY; | |
572 | } | |
573 | ||
574 | if (linfo.tag != op.tag) { | |
575 | CLS_LOG(20, "lock tag mismatch: current=%s, assert=%s", linfo.tag.c_str(), | |
576 | op.tag.c_str()); | |
577 | return -EBUSY; | |
578 | } | |
579 | ||
580 | entity_inst_t inst; | |
581 | r = cls_get_request_origin(hctx, &inst); | |
11fdf7f2 | 582 | ceph_assert(r == 0); |
7c673cae FG |
583 | |
584 | locker_id_t id; | |
585 | id.cookie = op.cookie; | |
586 | id.locker = inst.name; | |
587 | ||
588 | map<locker_id_t, locker_info_t>::iterator iter = linfo.lockers.find(id); | |
589 | if (iter == linfo.lockers.end()) { | |
590 | CLS_LOG(20, "not locked by client"); | |
591 | return -EBUSY; | |
592 | } | |
593 | ||
594 | id.cookie = op.new_cookie; | |
595 | if (linfo.lockers.count(id) != 0) { | |
596 | CLS_LOG(20, "lock cookie in-use"); | |
597 | return -EBUSY; | |
598 | } | |
599 | ||
600 | locker_info_t locker_info(iter->second); | |
601 | linfo.lockers.erase(iter); | |
602 | ||
603 | linfo.lockers[id] = locker_info; | |
604 | r = write_lock(hctx, op.name, linfo); | |
605 | if (r < 0) { | |
606 | CLS_ERR("Could not update lock info: %s", cpp_strerror(r).c_str()); | |
607 | return r; | |
608 | } | |
609 | return 0; | |
610 | } | |
611 | ||
612 | CLS_INIT(lock) | |
613 | { | |
614 | CLS_LOG(20, "Loaded lock class!"); | |
615 | ||
616 | cls_handle_t h_class; | |
617 | cls_method_handle_t h_lock_op; | |
618 | cls_method_handle_t h_unlock_op; | |
619 | cls_method_handle_t h_break_lock; | |
620 | cls_method_handle_t h_get_info; | |
621 | cls_method_handle_t h_list_locks; | |
622 | cls_method_handle_t h_assert_locked; | |
623 | cls_method_handle_t h_set_cookie; | |
624 | ||
625 | cls_register("lock", &h_class); | |
626 | cls_register_cxx_method(h_class, "lock", | |
627 | CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE, | |
628 | lock_op, &h_lock_op); | |
629 | cls_register_cxx_method(h_class, "unlock", | |
630 | CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE, | |
631 | unlock_op, &h_unlock_op); | |
632 | cls_register_cxx_method(h_class, "break_lock", | |
633 | CLS_METHOD_RD | CLS_METHOD_WR, | |
634 | break_lock, &h_break_lock); | |
635 | cls_register_cxx_method(h_class, "get_info", | |
636 | CLS_METHOD_RD, | |
637 | get_info, &h_get_info); | |
638 | cls_register_cxx_method(h_class, "list_locks", | |
639 | CLS_METHOD_RD, | |
640 | list_locks, &h_list_locks); | |
641 | cls_register_cxx_method(h_class, "assert_locked", | |
642 | CLS_METHOD_RD | CLS_METHOD_PROMOTE, | |
643 | assert_locked, &h_assert_locked); | |
644 | cls_register_cxx_method(h_class, "set_cookie", | |
645 | CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE, | |
646 | set_cookie, &h_set_cookie); | |
647 | ||
648 | return; | |
649 | } |