1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2023 Red Hat
6 #include "io-factory.h"
8 #include <linux/atomic.h>
9 #include <linux/blkdev.h>
10 #include <linux/err.h>
11 #include <linux/mount.h>
14 #include "memory-alloc.h"
18 * The I/O factory object manages access to index storage, which is a contiguous range of blocks on
21 * The factory holds the open device and is responsible for closing it. The factory has methods to
22 * make helper structures that can be used to access sections of the index.
25 struct block_device
*bdev
;
29 /* The buffered reader allows efficient I/O by reading page-sized segments into a buffer. */
30 struct buffered_reader
{
31 struct io_factory
*factory
;
32 struct dm_bufio_client
*client
;
33 struct dm_buffer
*buffer
;
35 sector_t block_number
;
40 #define MAX_READ_AHEAD_BLOCKS 4
43 * The buffered writer allows efficient I/O by buffering writes and committing page-sized segments
46 struct buffered_writer
{
47 struct io_factory
*factory
;
48 struct dm_bufio_client
*client
;
49 struct dm_buffer
*buffer
;
51 sector_t block_number
;
57 static void uds_get_io_factory(struct io_factory
*factory
)
59 atomic_inc(&factory
->ref_count
);
62 int uds_make_io_factory(struct block_device
*bdev
, struct io_factory
**factory_ptr
)
65 struct io_factory
*factory
;
67 result
= vdo_allocate(1, struct io_factory
, __func__
, &factory
);
68 if (result
!= VDO_SUCCESS
)
72 atomic_set_release(&factory
->ref_count
, 1);
74 *factory_ptr
= factory
;
78 int uds_replace_storage(struct io_factory
*factory
, struct block_device
*bdev
)
84 /* Free an I/O factory once all references have been released. */
85 void uds_put_io_factory(struct io_factory
*factory
)
87 if (atomic_add_return(-1, &factory
->ref_count
) <= 0)
91 size_t uds_get_writable_size(struct io_factory
*factory
)
93 return bdev_nr_bytes(factory
->bdev
);
96 /* Create a struct dm_bufio_client for an index region starting at offset. */
97 int uds_make_bufio(struct io_factory
*factory
, off_t block_offset
, size_t block_size
,
98 unsigned int reserved_buffers
, struct dm_bufio_client
**client_ptr
)
100 struct dm_bufio_client
*client
;
102 client
= dm_bufio_client_create(factory
->bdev
, block_size
, reserved_buffers
, 0,
105 return -PTR_ERR(client
);
107 dm_bufio_set_sector_offset(client
, block_offset
* SECTORS_PER_BLOCK
);
108 *client_ptr
= client
;
112 static void read_ahead(struct buffered_reader
*reader
, sector_t block_number
)
114 if (block_number
< reader
->limit
) {
115 sector_t read_ahead
= min((sector_t
) MAX_READ_AHEAD_BLOCKS
,
116 reader
->limit
- block_number
);
118 dm_bufio_prefetch(reader
->client
, block_number
, read_ahead
);
122 void uds_free_buffered_reader(struct buffered_reader
*reader
)
127 if (reader
->buffer
!= NULL
)
128 dm_bufio_release(reader
->buffer
);
130 dm_bufio_client_destroy(reader
->client
);
131 uds_put_io_factory(reader
->factory
);
135 /* Create a buffered reader for an index region starting at offset. */
136 int uds_make_buffered_reader(struct io_factory
*factory
, off_t offset
, u64 block_count
,
137 struct buffered_reader
**reader_ptr
)
140 struct dm_bufio_client
*client
= NULL
;
141 struct buffered_reader
*reader
= NULL
;
143 result
= uds_make_bufio(factory
, offset
, UDS_BLOCK_SIZE
, 1, &client
);
144 if (result
!= UDS_SUCCESS
)
147 result
= vdo_allocate(1, struct buffered_reader
, "buffered reader", &reader
);
148 if (result
!= VDO_SUCCESS
) {
149 dm_bufio_client_destroy(client
);
153 *reader
= (struct buffered_reader
) {
157 .limit
= block_count
,
163 read_ahead(reader
, 0);
164 uds_get_io_factory(factory
);
165 *reader_ptr
= reader
;
169 static int position_reader(struct buffered_reader
*reader
, sector_t block_number
,
172 struct dm_buffer
*buffer
= NULL
;
175 if ((reader
->end
== NULL
) || (block_number
!= reader
->block_number
)) {
176 if (block_number
>= reader
->limit
)
177 return UDS_OUT_OF_RANGE
;
179 if (reader
->buffer
!= NULL
)
180 dm_bufio_release(vdo_forget(reader
->buffer
));
182 data
= dm_bufio_read(reader
->client
, block_number
, &buffer
);
184 return -PTR_ERR(data
);
186 reader
->buffer
= buffer
;
187 reader
->start
= data
;
188 if (block_number
== reader
->block_number
+ 1)
189 read_ahead(reader
, block_number
+ 1);
192 reader
->block_number
= block_number
;
193 reader
->end
= reader
->start
+ offset
;
197 static size_t bytes_remaining_in_read_buffer(struct buffered_reader
*reader
)
199 return (reader
->end
== NULL
) ? 0 : reader
->start
+ UDS_BLOCK_SIZE
- reader
->end
;
202 static int reset_reader(struct buffered_reader
*reader
)
204 sector_t block_number
;
206 if (bytes_remaining_in_read_buffer(reader
) > 0)
209 block_number
= reader
->block_number
;
210 if (reader
->end
!= NULL
)
213 return position_reader(reader
, block_number
, 0);
216 int uds_read_from_buffered_reader(struct buffered_reader
*reader
, u8
*data
,
219 int result
= UDS_SUCCESS
;
223 result
= reset_reader(reader
);
224 if (result
!= UDS_SUCCESS
)
227 chunk_size
= min(length
, bytes_remaining_in_read_buffer(reader
));
228 memcpy(data
, reader
->end
, chunk_size
);
229 length
-= chunk_size
;
231 reader
->end
+= chunk_size
;
238 * Verify that the next data on the reader matches the required value. If the value matches, the
239 * matching contents are consumed. If the value does not match, the reader state is unchanged.
241 int uds_verify_buffered_data(struct buffered_reader
*reader
, const u8
*value
,
244 int result
= UDS_SUCCESS
;
246 sector_t start_block_number
= reader
->block_number
;
247 int start_offset
= reader
->end
- reader
->start
;
250 result
= reset_reader(reader
);
251 if (result
!= UDS_SUCCESS
) {
252 result
= UDS_CORRUPT_DATA
;
256 chunk_size
= min(length
, bytes_remaining_in_read_buffer(reader
));
257 if (memcmp(value
, reader
->end
, chunk_size
) != 0) {
258 result
= UDS_CORRUPT_DATA
;
262 length
-= chunk_size
;
264 reader
->end
+= chunk_size
;
267 if (result
!= UDS_SUCCESS
)
268 position_reader(reader
, start_block_number
, start_offset
);
273 /* Create a buffered writer for an index region starting at offset. */
274 int uds_make_buffered_writer(struct io_factory
*factory
, off_t offset
, u64 block_count
,
275 struct buffered_writer
**writer_ptr
)
278 struct dm_bufio_client
*client
= NULL
;
279 struct buffered_writer
*writer
;
281 result
= uds_make_bufio(factory
, offset
, UDS_BLOCK_SIZE
, 1, &client
);
282 if (result
!= UDS_SUCCESS
)
285 result
= vdo_allocate(1, struct buffered_writer
, "buffered writer", &writer
);
286 if (result
!= VDO_SUCCESS
) {
287 dm_bufio_client_destroy(client
);
291 *writer
= (struct buffered_writer
) {
295 .limit
= block_count
,
299 .error
= UDS_SUCCESS
,
302 uds_get_io_factory(factory
);
303 *writer_ptr
= writer
;
307 static size_t get_remaining_write_space(struct buffered_writer
*writer
)
309 return writer
->start
+ UDS_BLOCK_SIZE
- writer
->end
;
312 static int __must_check
prepare_next_buffer(struct buffered_writer
*writer
)
314 struct dm_buffer
*buffer
= NULL
;
317 if (writer
->block_number
>= writer
->limit
) {
318 writer
->error
= UDS_OUT_OF_RANGE
;
319 return UDS_OUT_OF_RANGE
;
322 data
= dm_bufio_new(writer
->client
, writer
->block_number
, &buffer
);
324 writer
->error
= -PTR_ERR(data
);
325 return writer
->error
;
328 writer
->buffer
= buffer
;
329 writer
->start
= data
;
334 static int flush_previous_buffer(struct buffered_writer
*writer
)
338 if (writer
->buffer
== NULL
)
339 return writer
->error
;
341 if (writer
->error
== UDS_SUCCESS
) {
342 available
= get_remaining_write_space(writer
);
345 memset(writer
->end
, 0, available
);
347 dm_bufio_mark_buffer_dirty(writer
->buffer
);
350 dm_bufio_release(writer
->buffer
);
351 writer
->buffer
= NULL
;
352 writer
->start
= NULL
;
354 writer
->block_number
++;
355 return writer
->error
;
358 void uds_free_buffered_writer(struct buffered_writer
*writer
)
365 flush_previous_buffer(writer
);
366 result
= -dm_bufio_write_dirty_buffers(writer
->client
);
367 if (result
!= UDS_SUCCESS
)
368 vdo_log_warning_strerror(result
, "%s: failed to sync storage", __func__
);
370 dm_bufio_client_destroy(writer
->client
);
371 uds_put_io_factory(writer
->factory
);
376 * Append data to the buffer, writing as needed. If no data is provided, zeros are written instead.
377 * If a write error occurs, it is recorded and returned on every subsequent write attempt.
379 int uds_write_to_buffered_writer(struct buffered_writer
*writer
, const u8
*data
,
382 int result
= writer
->error
;
385 while ((length
> 0) && (result
== UDS_SUCCESS
)) {
386 if (writer
->buffer
== NULL
) {
387 result
= prepare_next_buffer(writer
);
391 chunk_size
= min(length
, get_remaining_write_space(writer
));
393 memset(writer
->end
, 0, chunk_size
);
395 memcpy(writer
->end
, data
, chunk_size
);
399 length
-= chunk_size
;
400 writer
->end
+= chunk_size
;
402 if (get_remaining_write_space(writer
) == 0)
403 result
= uds_flush_buffered_writer(writer
);
409 int uds_flush_buffered_writer(struct buffered_writer
*writer
)
411 if (writer
->error
!= UDS_SUCCESS
)
412 return writer
->error
;
414 return flush_previous_buffer(writer
);