1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2 // vim: ts=8 sw=2 smarttab expandtab
4 #include "circular_journal_space.h"
6 #include <fmt/format.h>
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"
13 SET_SUBSYS(seastore_journal
);
15 namespace crimson::os::seastore::journal
{
17 std::ostream
&operator<<(std::ostream
&out
,
18 const CircularJournalSpace::cbj_header_t
&header
)
20 return out
<< "cbj_header_t("
21 << ", dirty_tail=" << header
.dirty_tail
22 << ", alloc_tail=" << header
.alloc_tail
26 CircularJournalSpace::CircularJournalSpace(RBMDevice
* device
) : device(device
) {}
28 bool CircularJournalSpace::needs_roll(std::size_t length
) const {
29 if (length
+ get_rbm_addr(get_written_to()) > get_journal_end()) {
35 extent_len_t
CircularJournalSpace::get_block_size() const {
36 return device
->get_block_size();
39 CircularJournalSpace::roll_ertr::future
<> CircularJournalSpace::roll() {
40 paddr_t paddr
= convert_abs_addr_to_paddr(
43 auto seq
= get_written_to();
45 journal_seq_t
{++seq
.segment_seq
, paddr
});
46 return roll_ertr::now();
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");
57 assert(encoded_size
+ get_rbm_addr(get_written_to())
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(
68 journal_seq_t
{get_written_to().segment_seq
, paddr
});
69 DEBUG("{}, target {}", to_write
.length(), target
);
71 auto write_result
= write_result_t
{
75 return device_write_bl(target
, to_write
76 ).safe_then([this, target
,
80 DEBUG("commit target {} used_size {} written length {}",
81 target
, get_records_used_size(), length
);
84 base_ertr::pass_further
{},
85 crimson::ct_error::assert_all
{ "Invalid error" }
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();
95 LOG_PREFIX(CircularJournalSpace::open
);
98 CircularJournalSpace::cbj_header_t head
;
99 assert(device
->get_journal_size());
102 convert_abs_addr_to_paddr(
104 device
->get_device_id())};
105 head
.alloc_tail
= head
.dirty_tail
;
108 set_written_to(head
.dirty_tail
);
111 "initialize header block in CircularJournalSpace length {}",
114 ).safe_then([this]() {
116 open_ertr::ready_future_marker
{},
119 open_ertr::pass_further
{},
120 crimson::ct_error::assert_all
{
121 "Invalid error write_header"
125 ceph_assert(initialized
);
126 if (written_to
.segment_seq
== NULL_SEG_SEQ
) {
127 written_to
.segment_seq
= 0;
130 open_ertr::ready_future_marker
{},
134 ceph::bufferlist
CircularJournalSpace::encode_header()
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
>(),
143 ceph_le32 header_crc_le
;
144 header_crc_le
= header_crc
;
145 header_crc_filler
.copy_in(
147 reinterpret_cast<const char *>(&header_crc_le
));
151 CircularJournalSpace::write_ertr::future
<> CircularJournalSpace::device_write_bl(
152 rbm_abs_addr offset
, bufferlist
&bl
)
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();
160 "overwrite in CircularJournalSpace, offset {}, length {}",
163 return device
->writev(offset
, bl
165 write_ertr::pass_further
{},
166 crimson::ct_error::assert_all
{ "Invalid error device->write" }
170 CircularJournalSpace::read_header_ret
171 CircularJournalSpace::read_header()
173 LOG_PREFIX(CircularJournalSpace::read_header
);
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
183 auto bp
= bl
.cbegin();
184 cbj_header_t cbj_header
;
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();
191 auto bliter
= bl
.cbegin();
192 auto test_crc
= bliter
.crc32c(
193 ceph::encoded_sizeof_bounded
<cbj_header_t
>(),
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
{},
204 return read_header_ret(
205 read_header_ertr::ready_future_marker
{},
206 std::make_pair(cbj_header
, bl
)
211 CircularJournalSpace::write_ertr::future
<>
212 CircularJournalSpace::write_header()
214 LOG_PREFIX(CircularJournalSpace::write_header
);
215 ceph::bufferlist bl
= encode_header();
216 ceph_assert(bl
.length() <= get_block_size());
218 "sync header of CircularJournalSpace, length {}",
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
)
227 write_ertr::pass_further
{},
228 crimson::ct_error::assert_all
{ "Invalid error device->write" }