]>
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 "librbd/object_map/LockRequest.h" | |
5 | #include "cls/lock/cls_lock_client.h" | |
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
8 | #include "librbd/ImageCtx.h" | |
9 | #include "librbd/ObjectMap.h" | |
10 | #include "librbd/Utils.h" | |
11 | ||
12 | #define dout_subsys ceph_subsys_rbd | |
13 | #undef dout_prefix | |
14 | #define dout_prefix *_dout << "librbd::object_map::LockRequest: " | |
15 | ||
16 | namespace librbd { | |
17 | namespace object_map { | |
18 | ||
19 | using util::create_rados_callback; | |
20 | ||
21 | template <typename I> | |
22 | LockRequest<I>::LockRequest(I &image_ctx, Context *on_finish) | |
23 | : m_image_ctx(image_ctx), m_on_finish(on_finish), m_broke_lock(false) { | |
24 | } | |
25 | ||
26 | template <typename I> | |
27 | void LockRequest<I>::send() { | |
28 | send_lock(); | |
29 | } | |
30 | ||
31 | template <typename I> | |
32 | void LockRequest<I>::send_lock() { | |
33 | CephContext *cct = m_image_ctx.cct; | |
34 | std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, CEPH_NOSNAP)); | |
35 | ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << dendl; | |
36 | ||
37 | librados::ObjectWriteOperation op; | |
38 | rados::cls::lock::lock(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "", "", | |
39 | utime_t(), 0); | |
40 | ||
41 | using klass = LockRequest<I>; | |
42 | librados::AioCompletion *rados_completion = | |
43 | create_rados_callback<klass, &klass::handle_lock>(this); | |
44 | int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op); | |
11fdf7f2 | 45 | ceph_assert(r == 0); |
7c673cae FG |
46 | rados_completion->release(); |
47 | } | |
48 | ||
49 | template <typename I> | |
50 | Context *LockRequest<I>::handle_lock(int *ret_val) { | |
51 | CephContext *cct = m_image_ctx.cct; | |
52 | ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl; | |
53 | ||
54 | if (*ret_val == 0) { | |
55 | return m_on_finish; | |
56 | } else if (*ret_val == -EEXIST) { | |
57 | // already locked by myself | |
58 | *ret_val = 0; | |
59 | return m_on_finish; | |
60 | } else if (m_broke_lock || *ret_val != -EBUSY) { | |
61 | lderr(cct) << "failed to lock object map: " << cpp_strerror(*ret_val) | |
62 | << dendl; | |
63 | *ret_val = 0; | |
64 | return m_on_finish; | |
65 | } | |
66 | ||
67 | send_get_lock_info(); | |
68 | return nullptr; | |
69 | } | |
70 | ||
71 | template <typename I> | |
72 | void LockRequest<I>::send_get_lock_info() { | |
73 | CephContext *cct = m_image_ctx.cct; | |
74 | std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, CEPH_NOSNAP)); | |
75 | ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << dendl; | |
76 | ||
77 | librados::ObjectReadOperation op; | |
78 | rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME); | |
79 | ||
80 | using klass = LockRequest<I>; | |
81 | librados::AioCompletion *rados_completion = | |
82 | create_rados_callback<klass, &klass::handle_get_lock_info>(this); | |
83 | int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op, &m_out_bl); | |
11fdf7f2 | 84 | ceph_assert(r == 0); |
7c673cae FG |
85 | rados_completion->release(); |
86 | } | |
87 | ||
88 | template <typename I> | |
89 | Context *LockRequest<I>::handle_get_lock_info(int *ret_val) { | |
90 | CephContext *cct = m_image_ctx.cct; | |
91 | ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl; | |
92 | ||
93 | if (*ret_val == -ENOENT) { | |
94 | send_lock(); | |
95 | return nullptr; | |
96 | } | |
97 | ||
98 | ClsLockType lock_type; | |
99 | std::string lock_tag; | |
100 | if (*ret_val == 0) { | |
11fdf7f2 | 101 | auto it = m_out_bl.cbegin(); |
7c673cae FG |
102 | *ret_val = rados::cls::lock::get_lock_info_finish(&it, &m_lockers, |
103 | &lock_type, &lock_tag); | |
104 | } | |
105 | if (*ret_val < 0) { | |
106 | lderr(cct) << "failed to list object map locks: " << cpp_strerror(*ret_val) | |
107 | << dendl; | |
108 | *ret_val = 0; | |
109 | return m_on_finish; | |
110 | } | |
111 | ||
112 | send_break_locks(); | |
113 | return nullptr; | |
114 | } | |
115 | ||
116 | template <typename I> | |
117 | void LockRequest<I>::send_break_locks() { | |
118 | CephContext *cct = m_image_ctx.cct; | |
119 | std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, CEPH_NOSNAP)); | |
120 | ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << ", " | |
121 | << "num_lockers=" << m_lockers.size() << dendl; | |
122 | ||
123 | librados::ObjectWriteOperation op; | |
124 | for (auto &locker : m_lockers) { | |
125 | rados::cls::lock::break_lock(&op, RBD_LOCK_NAME, locker.first.cookie, | |
126 | locker.first.locker); | |
127 | } | |
128 | ||
129 | using klass = LockRequest<I>; | |
130 | librados::AioCompletion *rados_completion = | |
131 | create_rados_callback<klass, &klass::handle_break_locks>(this); | |
132 | int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op); | |
11fdf7f2 | 133 | ceph_assert(r == 0); |
7c673cae FG |
134 | rados_completion->release(); |
135 | } | |
136 | ||
137 | template <typename I> | |
138 | Context *LockRequest<I>::handle_break_locks(int *ret_val) { | |
139 | CephContext *cct = m_image_ctx.cct; | |
140 | ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl; | |
141 | ||
142 | m_broke_lock = true; | |
143 | if (*ret_val == 0 || *ret_val == -ENOENT) { | |
144 | send_lock(); | |
145 | return nullptr; | |
146 | } | |
147 | ||
148 | lderr(cct) << "failed to break object map lock: " << cpp_strerror(*ret_val) | |
149 | << dendl; | |
150 | *ret_val = 0; | |
151 | return m_on_finish; | |
152 | } | |
153 | ||
154 | } // namespace object_map | |
155 | } // namespace librbd | |
156 | ||
157 | template class librbd::object_map::LockRequest<librbd::ImageCtx>; |