]>
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/operation/RenameRequest.h" | |
5 | #include "common/dout.h" | |
6 | #include "common/errno.h" | |
7 | #include "include/rados/librados.hpp" | |
8 | #include "librbd/ImageCtx.h" | |
9 | #include "librbd/internal.h" | |
10 | #include "librbd/Utils.h" | |
11 | ||
12 | #define dout_subsys ceph_subsys_rbd | |
13 | #undef dout_prefix | |
14 | #define dout_prefix *_dout << "librbd::operation::RenameRequest: " | |
15 | ||
16 | namespace librbd { | |
17 | namespace operation { | |
18 | ||
19 | namespace { | |
20 | ||
21 | template <typename I> | |
22 | std::ostream& operator<<(std::ostream& os, | |
23 | const typename RenameRequest<I>::State& state) { | |
24 | switch(state) { | |
25 | case RenameRequest<I>::STATE_READ_SOURCE_HEADER: | |
26 | os << "READ_SOURCE_HEADER"; | |
27 | break; | |
28 | case RenameRequest<I>::STATE_WRITE_DEST_HEADER: | |
29 | os << "WRITE_DEST_HEADER"; | |
30 | break; | |
31 | case RenameRequest<I>::STATE_UPDATE_DIRECTORY: | |
32 | os << "UPDATE_DIRECTORY"; | |
33 | break; | |
34 | case RenameRequest<I>::STATE_REMOVE_SOURCE_HEADER: | |
35 | os << "REMOVE_SOURCE_HEADER"; | |
36 | break; | |
37 | default: | |
38 | os << "UNKNOWN (" << static_cast<uint32_t>(state) << ")"; | |
39 | break; | |
40 | } | |
41 | return os; | |
42 | } | |
43 | ||
44 | } // anonymous namespace | |
45 | ||
46 | template <typename I> | |
47 | RenameRequest<I>::RenameRequest(I &image_ctx, Context *on_finish, | |
48 | const std::string &dest_name) | |
49 | : Request<I>(image_ctx, on_finish), m_dest_name(dest_name), | |
50 | m_source_oid(image_ctx.old_format ? util::old_header_name(image_ctx.name) : | |
51 | util::id_obj_name(image_ctx.name)), | |
52 | m_dest_oid(image_ctx.old_format ? util::old_header_name(dest_name) : | |
53 | util::id_obj_name(dest_name)) { | |
54 | } | |
55 | ||
56 | template <typename I> | |
57 | void RenameRequest<I>::send_op() { | |
58 | send_read_source_header(); | |
59 | } | |
60 | ||
61 | template <typename I> | |
62 | bool RenameRequest<I>::should_complete(int r) { | |
63 | I &image_ctx = this->m_image_ctx; | |
64 | CephContext *cct = image_ctx.cct; | |
65 | ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", " | |
66 | << "r=" << r << dendl; | |
67 | r = filter_state_return_code(r); | |
68 | if (r < 0) { | |
69 | if (r == -EEXIST) { | |
70 | ldout(cct, 1) << "image already exists" << dendl; | |
71 | } else { | |
72 | lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl; | |
73 | } | |
74 | return true; | |
75 | } | |
76 | ||
b32b8144 FG |
77 | if (m_state == STATE_UPDATE_DIRECTORY) { |
78 | // update in-memory name before removing source header | |
7c673cae | 79 | apply(); |
b32b8144 | 80 | } else if (m_state == STATE_REMOVE_SOURCE_HEADER) { |
7c673cae FG |
81 | return true; |
82 | } | |
83 | ||
84 | RWLock::RLocker owner_lock(image_ctx.owner_lock); | |
85 | switch (m_state) { | |
86 | case STATE_READ_SOURCE_HEADER: | |
87 | send_write_destination_header(); | |
88 | break; | |
89 | case STATE_WRITE_DEST_HEADER: | |
90 | send_update_directory(); | |
91 | break; | |
92 | case STATE_UPDATE_DIRECTORY: | |
93 | send_remove_source_header(); | |
94 | break; | |
95 | default: | |
96 | assert(false); | |
97 | break; | |
98 | } | |
99 | return false; | |
100 | } | |
101 | ||
102 | template <typename I> | |
103 | int RenameRequest<I>::filter_state_return_code(int r) { | |
104 | I &image_ctx = this->m_image_ctx; | |
105 | CephContext *cct = image_ctx.cct; | |
106 | ||
b32b8144 FG |
107 | if (m_state == STATE_READ_SOURCE_HEADER && r == -ENOENT) { |
108 | RWLock::RLocker snap_locker(image_ctx.snap_lock); | |
109 | if (image_ctx.name == m_dest_name) { | |
110 | // signal that replay raced with itself | |
111 | return -EEXIST; | |
112 | } | |
113 | } else if (m_state == STATE_REMOVE_SOURCE_HEADER && r < 0) { | |
7c673cae FG |
114 | if (r != -ENOENT) { |
115 | lderr(cct) << "warning: couldn't remove old source object (" | |
116 | << m_source_oid << ")" << dendl; | |
117 | } | |
118 | return 0; | |
119 | } | |
120 | return r; | |
121 | } | |
122 | ||
123 | template <typename I> | |
124 | void RenameRequest<I>::send_read_source_header() { | |
125 | I &image_ctx = this->m_image_ctx; | |
126 | CephContext *cct = image_ctx.cct; | |
127 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
128 | m_state = STATE_READ_SOURCE_HEADER; | |
129 | ||
130 | librados::ObjectReadOperation op; | |
131 | op.read(0, 0, NULL, NULL); | |
132 | ||
133 | // TODO: old code read omap values but there are no omap values on the | |
134 | // old format header nor the new format id object | |
135 | librados::AioCompletion *rados_completion = this->create_callback_completion(); | |
136 | int r = image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op, | |
137 | &m_header_bl); | |
138 | assert(r == 0); | |
139 | rados_completion->release(); | |
140 | } | |
141 | ||
142 | template <typename I> | |
143 | void RenameRequest<I>::send_write_destination_header() { | |
144 | I &image_ctx = this->m_image_ctx; | |
145 | CephContext *cct = image_ctx.cct; | |
146 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
147 | m_state = STATE_WRITE_DEST_HEADER; | |
148 | ||
149 | librados::ObjectWriteOperation op; | |
150 | op.create(true); | |
151 | op.write_full(m_header_bl); | |
152 | ||
153 | librados::AioCompletion *rados_completion = this->create_callback_completion(); | |
154 | int r = image_ctx.md_ctx.aio_operate(m_dest_oid, rados_completion, &op); | |
155 | assert(r == 0); | |
156 | rados_completion->release(); | |
157 | } | |
158 | ||
159 | template <typename I> | |
160 | void RenameRequest<I>::send_update_directory() { | |
161 | I &image_ctx = this->m_image_ctx; | |
162 | CephContext *cct = image_ctx.cct; | |
163 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
164 | m_state = STATE_UPDATE_DIRECTORY; | |
165 | ||
166 | librados::ObjectWriteOperation op; | |
167 | if (image_ctx.old_format) { | |
168 | bufferlist cmd_bl; | |
169 | bufferlist empty_bl; | |
170 | ::encode(static_cast<__u8>(CEPH_OSD_TMAP_SET), cmd_bl); | |
171 | ::encode(m_dest_name, cmd_bl); | |
172 | ::encode(empty_bl, cmd_bl); | |
173 | ::encode(static_cast<__u8>(CEPH_OSD_TMAP_RM), cmd_bl); | |
174 | ::encode(image_ctx.name, cmd_bl); | |
175 | op.tmap_update(cmd_bl); | |
176 | } else { | |
177 | cls_client::dir_rename_image(&op, image_ctx.name, m_dest_name, | |
178 | image_ctx.id); | |
179 | } | |
180 | ||
181 | librados::AioCompletion *rados_completion = this->create_callback_completion(); | |
182 | int r = image_ctx.md_ctx.aio_operate(RBD_DIRECTORY, rados_completion, &op); | |
183 | assert(r == 0); | |
184 | rados_completion->release(); | |
185 | } | |
186 | ||
187 | template <typename I> | |
188 | void RenameRequest<I>::send_remove_source_header() { | |
189 | I &image_ctx = this->m_image_ctx; | |
190 | CephContext *cct = image_ctx.cct; | |
191 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
192 | m_state = STATE_REMOVE_SOURCE_HEADER; | |
193 | ||
194 | librados::ObjectWriteOperation op; | |
195 | op.remove(); | |
196 | ||
197 | librados::AioCompletion *rados_completion = this->create_callback_completion(); | |
198 | int r = image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op); | |
199 | assert(r == 0); | |
200 | rados_completion->release(); | |
201 | } | |
202 | ||
203 | template <typename I> | |
204 | void RenameRequest<I>::apply() { | |
205 | I &image_ctx = this->m_image_ctx; | |
206 | image_ctx.set_image_name(m_dest_name); | |
207 | } | |
208 | ||
209 | } // namespace operation | |
210 | } // namespace librbd | |
211 | ||
212 | template class librbd::operation::RenameRequest<librbd::ImageCtx>; |