]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- |
2 | // vim: ts=8 sw=2 smarttab expandtab | |
3 | ||
4 | #include "circular_journal_space.h" | |
5 | ||
6 | #include <fmt/format.h> | |
7 | #include <fmt/os.h> | |
8 | ||
9 | #include "crimson/os/seastore/logging.h" | |
10 | #include "crimson/os/seastore/async_cleaner.h" | |
11 | #include "crimson/os/seastore/journal/circular_bounded_journal.h" | |
12 | ||
13 | SET_SUBSYS(seastore_journal); | |
14 | ||
15 | namespace crimson::os::seastore::journal { | |
16 | ||
17 | std::ostream &operator<<(std::ostream &out, | |
18 | const CircularJournalSpace::cbj_header_t &header) | |
19 | { | |
20 | return out << "cbj_header_t(" | |
21 | << ", dirty_tail=" << header.dirty_tail | |
22 | << ", alloc_tail=" << header.alloc_tail | |
23 | << ")"; | |
24 | } | |
25 | ||
26 | CircularJournalSpace::CircularJournalSpace(RBMDevice * device) : device(device) {} | |
27 | ||
28 | bool CircularJournalSpace::needs_roll(std::size_t length) const { | |
29 | if (length + get_rbm_addr(get_written_to()) > get_journal_end()) { | |
30 | return true; | |
31 | } | |
32 | return false; | |
33 | } | |
34 | ||
35 | extent_len_t CircularJournalSpace::get_block_size() const { | |
36 | return device->get_block_size(); | |
37 | } | |
38 | ||
39 | CircularJournalSpace::roll_ertr::future<> CircularJournalSpace::roll() { | |
40 | paddr_t paddr = convert_abs_addr_to_paddr( | |
41 | get_records_start(), | |
42 | get_device_id()); | |
43 | auto seq = get_written_to(); | |
44 | set_written_to( | |
45 | journal_seq_t{++seq.segment_seq, paddr}); | |
46 | return roll_ertr::now(); | |
47 | } | |
48 | ||
49 | CircularJournalSpace::write_ret | |
50 | CircularJournalSpace::write(ceph::bufferlist&& to_write) { | |
51 | LOG_PREFIX(CircularJournalSpace::write); | |
52 | assert(get_written_to().segment_seq != NULL_SEG_SEQ); | |
53 | auto encoded_size = to_write.length(); | |
54 | if (encoded_size > get_records_available_size()) { | |
55 | ceph_abort("should be impossible with EPM reservation"); | |
56 | } | |
57 | assert(encoded_size + get_rbm_addr(get_written_to()) | |
58 | < get_journal_end()); | |
59 | ||
60 | journal_seq_t j_seq = get_written_to(); | |
61 | auto target = get_rbm_addr(get_written_to()); | |
62 | auto new_written_to = target + encoded_size; | |
63 | assert(new_written_to < get_journal_end()); | |
64 | paddr_t paddr = convert_abs_addr_to_paddr( | |
65 | new_written_to, | |
66 | get_device_id()); | |
67 | set_written_to( | |
68 | journal_seq_t{get_written_to().segment_seq, paddr}); | |
69 | DEBUG("{}, target {}", to_write.length(), target); | |
70 | ||
71 | auto write_result = write_result_t{ | |
72 | j_seq, | |
73 | encoded_size | |
74 | }; | |
75 | return device_write_bl(target, to_write | |
76 | ).safe_then([this, target, | |
77 | length=encoded_size, | |
78 | write_result, | |
79 | FNAME] { | |
80 | DEBUG("commit target {} used_size {} written length {}", | |
81 | target, get_records_used_size(), length); | |
82 | return write_result; | |
83 | }).handle_error( | |
84 | base_ertr::pass_further{}, | |
85 | crimson::ct_error::assert_all{ "Invalid error" } | |
86 | ); | |
87 | } | |
88 | ||
89 | CircularJournalSpace::open_ret CircularJournalSpace::open(bool is_mkfs) { | |
90 | std::ostringstream oss; | |
91 | oss << device_id_printer_t{get_device_id()}; | |
92 | print_name = oss.str(); | |
93 | ||
94 | if (is_mkfs) { | |
95 | LOG_PREFIX(CircularJournalSpace::open); | |
96 | assert(device); | |
97 | ceph::bufferlist bl; | |
98 | CircularJournalSpace::cbj_header_t head; | |
99 | assert(device->get_journal_size()); | |
100 | head.dirty_tail = | |
101 | journal_seq_t{0, | |
102 | convert_abs_addr_to_paddr( | |
103 | get_records_start(), | |
104 | device->get_device_id())}; | |
105 | head.alloc_tail = head.dirty_tail; | |
106 | encode(head, bl); | |
107 | header = head; | |
108 | set_written_to(head.dirty_tail); | |
109 | initialized = true; | |
110 | DEBUG( | |
111 | "initialize header block in CircularJournalSpace length {}", | |
112 | bl.length()); | |
113 | return write_header( | |
114 | ).safe_then([this]() { | |
115 | return open_ret( | |
116 | open_ertr::ready_future_marker{}, | |
117 | get_written_to()); | |
118 | }).handle_error( | |
119 | open_ertr::pass_further{}, | |
120 | crimson::ct_error::assert_all{ | |
121 | "Invalid error write_header" | |
122 | } | |
123 | ); | |
124 | } | |
125 | ceph_assert(initialized); | |
126 | if (written_to.segment_seq == NULL_SEG_SEQ) { | |
127 | written_to.segment_seq = 0; | |
128 | } | |
129 | return open_ret( | |
130 | open_ertr::ready_future_marker{}, | |
131 | get_written_to()); | |
132 | } | |
133 | ||
134 | ceph::bufferlist CircularJournalSpace::encode_header() | |
135 | { | |
136 | bufferlist bl; | |
137 | encode(header, bl); | |
138 | auto header_crc_filler = bl.append_hole(sizeof(checksum_t)); | |
139 | auto bliter = bl.cbegin(); | |
140 | auto header_crc = bliter.crc32c( | |
141 | ceph::encoded_sizeof_bounded<cbj_header_t>(), | |
142 | -1); | |
143 | ceph_le32 header_crc_le; | |
144 | header_crc_le = header_crc; | |
145 | header_crc_filler.copy_in( | |
146 | sizeof(checksum_t), | |
147 | reinterpret_cast<const char *>(&header_crc_le)); | |
148 | return bl; | |
149 | } | |
150 | ||
151 | CircularJournalSpace::write_ertr::future<> CircularJournalSpace::device_write_bl( | |
152 | rbm_abs_addr offset, bufferlist &bl) | |
153 | { | |
154 | LOG_PREFIX(CircularJournalSpace::device_write_bl); | |
155 | auto length = bl.length(); | |
156 | if (offset + length > get_journal_end()) { | |
157 | return crimson::ct_error::erange::make(); | |
158 | } | |
159 | DEBUG( | |
160 | "overwrite in CircularJournalSpace, offset {}, length {}", | |
161 | offset, | |
162 | length); | |
163 | return device->writev(offset, bl | |
164 | ).handle_error( | |
165 | write_ertr::pass_further{}, | |
166 | crimson::ct_error::assert_all{ "Invalid error device->write" } | |
167 | ); | |
168 | } | |
169 | ||
170 | CircularJournalSpace::read_header_ret | |
171 | CircularJournalSpace::read_header() | |
172 | { | |
173 | LOG_PREFIX(CircularJournalSpace::read_header); | |
174 | assert(device); | |
175 | auto bptr = bufferptr(ceph::buffer::create_page_aligned( | |
176 | device->get_block_size())); | |
177 | DEBUG("reading {}", device->get_journal_start()); | |
178 | return device->read(device->get_journal_start(), bptr | |
179 | ).safe_then([bptr, FNAME]() mutable | |
180 | -> read_header_ret { | |
181 | bufferlist bl; | |
182 | bl.append(bptr); | |
183 | auto bp = bl.cbegin(); | |
184 | cbj_header_t cbj_header; | |
185 | try { | |
186 | decode(cbj_header, bp); | |
187 | } catch (ceph::buffer::error &e) { | |
188 | ERROR("unable to read header block"); | |
189 | return crimson::ct_error::enoent::make(); | |
190 | } | |
191 | auto bliter = bl.cbegin(); | |
192 | auto test_crc = bliter.crc32c( | |
193 | ceph::encoded_sizeof_bounded<cbj_header_t>(), | |
194 | -1); | |
195 | ceph_le32 recorded_crc_le; | |
196 | decode(recorded_crc_le, bliter); | |
197 | uint32_t recorded_crc = recorded_crc_le; | |
198 | if (test_crc != recorded_crc) { | |
199 | ERROR("error, header crc mismatch."); | |
200 | return read_header_ret( | |
201 | read_header_ertr::ready_future_marker{}, | |
202 | std::nullopt); | |
203 | } | |
204 | return read_header_ret( | |
205 | read_header_ertr::ready_future_marker{}, | |
206 | std::make_pair(cbj_header, bl) | |
207 | ); | |
208 | }); | |
209 | } | |
210 | ||
211 | CircularJournalSpace::write_ertr::future<> | |
212 | CircularJournalSpace::write_header() | |
213 | { | |
214 | LOG_PREFIX(CircularJournalSpace::write_header); | |
215 | ceph::bufferlist bl = encode_header(); | |
216 | ceph_assert(bl.length() <= get_block_size()); | |
217 | DEBUG( | |
218 | "sync header of CircularJournalSpace, length {}", | |
219 | bl.length()); | |
220 | assert(device); | |
221 | auto iter = bl.begin(); | |
222 | assert(bl.length() < get_block_size()); | |
223 | bufferptr bp = bufferptr(ceph::buffer::create_page_aligned(get_block_size())); | |
224 | iter.copy(bl.length(), bp.c_str()); | |
225 | return device->write(device->get_journal_start(), std::move(bp) | |
226 | ).handle_error( | |
227 | write_ertr::pass_further{}, | |
228 | crimson::ct_error::assert_all{ "Invalid error device->write" } | |
229 | ); | |
230 | } | |
231 | ||
232 | } |