1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include <boost/intrusive_ptr.hpp>
7 #include <boost/smart_ptr/intrusive_ref_counter.hpp>
9 #include <seastar/core/file.hh>
10 #include <seastar/core/future.hh>
11 #include <seastar/core/reactor.hh>
13 #include "crimson/common/layout.h"
15 #include "crimson/os/seastore/segment_manager.h"
17 namespace crimson::os::seastore::segment_manager::block
{
19 using write_ertr
= crimson::errorator
<
20 crimson::ct_error::input_output_error
>;
21 using read_ertr
= crimson::errorator
<
22 crimson::ct_error::input_output_error
>;
27 * Tracks lifecycle state of each segment using space at the beginning
30 class SegmentStateTracker
{
31 using segment_state_t
= Segment::segment_state_t
;
35 using L
= absl::container_internal::Layout
<uint8_t>;
39 static size_t get_raw_size(size_t segments
, size_t block_size
) {
40 return p2roundup(segments
, block_size
);
43 SegmentStateTracker(size_t segments
, size_t block_size
)
44 : bptr(ceph::buffer::create_page_aligned(
45 get_raw_size(segments
, block_size
))),
50 static_cast<char>(segment_state_t::EMPTY
),
54 size_t get_size() const {
58 size_t get_capacity() const {
62 segment_state_t
get(device_segment_id_t offset
) const {
63 assert(offset
< get_capacity());
64 return static_cast<segment_state_t
>(
65 layout
.template Pointer
<0>(
66 bptr
.c_str())[offset
]);
69 void set(device_segment_id_t offset
, segment_state_t state
) {
70 assert(offset
< get_capacity());
71 layout
.template Pointer
<0>(bptr
.c_str())[offset
] =
72 static_cast<uint8_t>(state
);
75 write_ertr::future
<> write_out(
76 device_id_t device_id
,
77 seastar::file
&device
,
80 read_ertr::future
<> read_in(
81 device_id_t device_id
,
82 seastar::file
&device
,
86 class BlockSegmentManager
;
87 class BlockSegment final
: public Segment
{
88 friend class BlockSegmentManager
;
89 BlockSegmentManager
&manager
;
90 const segment_id_t id
;
91 segment_off_t write_pointer
= 0;
93 BlockSegment(BlockSegmentManager
&manager
, segment_id_t id
);
95 segment_id_t
get_segment_id() const final
{ return id
; }
96 segment_off_t
get_write_capacity() const final
;
97 segment_off_t
get_write_ptr() const final
{ return write_pointer
; }
98 close_ertr::future
<> close() final
;
99 write_ertr::future
<> write(segment_off_t offset
, ceph::bufferlist bl
) final
;
100 write_ertr::future
<> advance_wp(segment_off_t offset
) final
;
106 * BlockSegmentManager
108 * Implements SegmentManager on a conventional block device.
109 * SegmentStateTracker uses space at the start of the device to store
110 * state analagous to that of the segments of a zns device.
112 class BlockSegmentManager final
: public SegmentManager
{
113 // interfaces used by Device
115 seastar::future
<> start() {
116 return shard_devices
.start(device_path
, superblock
.config
.spec
.dtype
);
119 seastar::future
<> stop() {
120 return shard_devices
.stop();
123 Device
& get_sharded_device() final
{
124 return shard_devices
.local();
126 mount_ret
mount() final
;
128 mkfs_ret
mkfs(device_config_t
) final
;
129 // interfaces used by each shard device
131 close_ertr::future
<> close();
134 const std::string
&path
,
136 : device_path(path
) {
137 ceph_assert(get_device_type() == device_type_t::NONE
);
138 superblock
.config
.spec
.dtype
= dtype
;
141 ~BlockSegmentManager();
143 open_ertr::future
<SegmentRef
> open(segment_id_t id
) final
;
145 release_ertr::future
<> release(segment_id_t id
) final
;
147 read_ertr::future
<> read(
150 ceph::bufferptr
&out
) final
;
152 device_type_t
get_device_type() const final
{
153 return superblock
.config
.spec
.dtype
;
155 size_t get_available_size() const final
{
156 return shard_info
.size
;
158 extent_len_t
get_block_size() const {
159 return superblock
.block_size
;
161 segment_off_t
get_segment_size() const {
162 return superblock
.segment_size
;
165 device_id_t
get_device_id() const final
{
166 assert(device_id
<= DEVICE_ID_MAX_VALID
);
169 secondary_device_set_t
& get_secondary_devices() final
{
170 return superblock
.config
.secondary_devices
;
172 // public so tests can bypass segment interface when simpler
173 Segment::write_ertr::future
<> segment_write(
176 bool ignore_check
=false);
178 magic_t
get_magic() const final
{
179 return superblock
.config
.spec
.magic
;
183 friend class BlockSegment
;
184 using segment_state_t
= Segment::segment_state_t
;
190 void increment(uint64_t read_bytes
) {
199 effort_t metadata_write
;
200 uint64_t opened_segments
;
201 uint64_t closed_segments
;
202 uint64_t closed_segments_unused_bytes
;
203 uint64_t released_segments
;
211 closed_segments_unused_bytes
= 0;
212 released_segments
= 0;
216 void register_metrics();
217 seastar::metrics::metric_group metrics
;
219 std::string device_path
;
220 std::unique_ptr
<SegmentStateTracker
> tracker
;
221 block_shard_info_t shard_info
;
222 block_sm_superblock_t superblock
;
223 seastar::file device
;
225 void set_device_id(device_id_t id
) {
226 assert(id
<= DEVICE_ID_MAX_VALID
);
227 assert(device_id
== DEVICE_ID_NULL
||
231 device_id_t device_id
= DEVICE_ID_NULL
;
233 size_t get_offset(paddr_t addr
) {
234 auto& seg_addr
= addr
.as_seg_paddr();
235 return shard_info
.first_segment_offset
+
236 (seg_addr
.get_segment_id().device_segment_id() * superblock
.segment_size
) +
237 seg_addr
.get_segment_off();
240 const seastore_meta_t
&get_meta() const {
241 return superblock
.config
.meta
;
244 std::vector
<segment_state_t
> segment_state
;
246 char *buffer
= nullptr;
248 Segment::close_ertr::future
<> segment_close(
249 segment_id_t id
, segment_off_t write_pointer
);
253 mkfs_ret
primary_mkfs(device_config_t
);
255 mkfs_ret
shard_mkfs();
257 mount_ret
shard_mount();
259 seastar::sharded
<BlockSegmentManager
> shard_devices
;