1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/dout.h"
5 #include "common/errno.h"
6 #include "include/ceph_assert.h"
7 #include "librbd/Utils.h"
8 #include "common/Timer.h"
9 #include "common/WorkQueue.h"
10 #include "journal/Settings.h"
11 #include "librbd/journal/CreateRequest.h"
12 #include "librbd/journal/RemoveRequest.h"
14 #define dout_subsys ceph_subsys_rbd
16 #define dout_prefix *_dout << "librbd::Journal::CreateRequest: "
20 using util::create_context_callback
;
25 CreateRequest
<I
>::CreateRequest(IoCtx
&ioctx
, const std::string
&imageid
,
26 uint8_t order
, uint8_t splay_width
,
27 const std::string
&object_pool
,
28 uint64_t tag_class
, TagData
&tag_data
,
29 const std::string
&client_id
,
30 ContextWQ
*op_work_queue
,
32 : m_ioctx(ioctx
), m_image_id(imageid
), m_order(order
),
33 m_splay_width(splay_width
), m_object_pool(object_pool
),
34 m_tag_class(tag_class
), m_tag_data(tag_data
), m_image_client_id(client_id
),
35 m_op_work_queue(op_work_queue
), m_on_finish(on_finish
) {
36 m_cct
= reinterpret_cast<CephContext
*>(m_ioctx
.cct());
40 void CreateRequest
<I
>::send() {
41 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
43 if (m_order
> 64 || m_order
< 12) {
44 lderr(m_cct
) << "order must be in the range [12, 64]" << dendl
;
48 if (m_splay_width
== 0) {
57 void CreateRequest
<I
>::get_pool_id() {
58 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
60 if (m_object_pool
.empty()) {
65 librados::Rados
rados(m_ioctx
);
67 int r
= rados
.ioctx_create(m_object_pool
.c_str(), data_ioctx
);
69 lderr(m_cct
) << "failed to create journal: "
70 << "error opening journal object pool '" << m_object_pool
71 << "': " << cpp_strerror(r
) << dendl
;
75 data_ioctx
.set_namespace(m_ioctx
.get_namespace());
77 m_pool_id
= data_ioctx
.get_id();
82 void CreateRequest
<I
>::create_journal() {
83 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
85 ImageCtx::get_timer_instance(m_cct
, &m_timer
, &m_timer_lock
);
86 m_journaler
= new Journaler(m_op_work_queue
, m_timer
, m_timer_lock
, m_ioctx
,
87 m_image_id
, m_image_client_id
, {}, nullptr);
89 using klass
= CreateRequest
<I
>;
90 Context
*ctx
= create_context_callback
<klass
, &klass::handle_create_journal
>(this);
92 m_journaler
->create(m_order
, m_splay_width
, m_pool_id
, ctx
);
96 Context
*CreateRequest
<I
>::handle_create_journal(int *result
) {
97 ldout(m_cct
, 20) << __func__
<< ": r=" << *result
<< dendl
;
100 lderr(m_cct
) << "failed to create journal: " << cpp_strerror(*result
) << dendl
;
101 shut_down_journaler(*result
);
105 allocate_journal_tag();
110 void CreateRequest
<I
>::allocate_journal_tag() {
111 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
113 using klass
= CreateRequest
<I
>;
114 Context
*ctx
= create_context_callback
<klass
, &klass::handle_journal_tag
>(this);
116 encode(m_tag_data
, m_bl
);
117 m_journaler
->allocate_tag(m_tag_class
, m_bl
, &m_tag
, ctx
);
121 Context
*CreateRequest
<I
>::handle_journal_tag(int *result
) {
122 ldout(m_cct
, 20) << __func__
<< ": r=" << *result
<< dendl
;
125 lderr(m_cct
) << "failed to allocate tag: " << cpp_strerror(*result
) << dendl
;
126 shut_down_journaler(*result
);
135 void CreateRequest
<I
>::register_client() {
136 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
139 encode(ClientData
{ImageClientMeta
{m_tag
.tag_class
}}, m_bl
);
141 using klass
= CreateRequest
<I
>;
142 Context
*ctx
= create_context_callback
<klass
, &klass::handle_register_client
>(this);
144 m_journaler
->register_client(m_bl
, ctx
);
148 Context
*CreateRequest
<I
>::handle_register_client(int *result
) {
149 ldout(m_cct
, 20) << __func__
<< ": r=" << *result
<< dendl
;
152 lderr(m_cct
) << "failed to register client: " << cpp_strerror(*result
) << dendl
;
155 shut_down_journaler(*result
);
160 void CreateRequest
<I
>::shut_down_journaler(int r
) {
161 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
165 using klass
= CreateRequest
<I
>;
166 Context
*ctx
= create_context_callback
<klass
, &klass::handle_journaler_shutdown
>(this);
168 m_journaler
->shut_down(ctx
);
172 Context
*CreateRequest
<I
>::handle_journaler_shutdown(int *result
) {
173 ldout(m_cct
, 20) << __func__
<< ": r=" << *result
<< dendl
;
176 lderr(m_cct
) << "failed to shut down journaler: " << cpp_strerror(*result
) << dendl
;
186 // there was an error during journal creation, so we rollback
187 // what ever was done. the easiest way to do this is to invoke
188 // journal remove state machine, although it's not the most
189 // cleanest approach when it comes to redundancy, but that's
190 // ok during the failure path.
196 void CreateRequest
<I
>::remove_journal() {
197 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
199 using klass
= CreateRequest
<I
>;
200 Context
*ctx
= create_context_callback
<klass
, &klass::handle_remove_journal
>(this);
202 RemoveRequest
<I
> *req
= RemoveRequest
<I
>::create(
203 m_ioctx
, m_image_id
, m_image_client_id
, m_op_work_queue
, ctx
);
208 Context
*CreateRequest
<I
>::handle_remove_journal(int *result
) {
209 ldout(m_cct
, 20) << __func__
<< ": r=" << *result
<< dendl
;
212 lderr(m_cct
) << "error cleaning up journal after creation failed: "
213 << cpp_strerror(*result
) << dendl
;
221 void CreateRequest
<I
>::complete(int r
) {
222 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
225 ldout(m_cct
, 20) << "done." << dendl
;
228 m_on_finish
->complete(r
);
232 } // namespace journal
233 } // namespace librbd
235 template class librbd::journal::CreateRequest
<librbd::ImageCtx
>;