drm/rockchip: Don't change hdmi reference clock rate
[drm/drm-misc.git] / drivers / md / dm-vdo / indexer / io-factory.c
blob1bee9d63dc0a692734cc6908809534dcc45bb158
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright 2023 Red Hat
4 */
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>
13 #include "logger.h"
14 #include "memory-alloc.h"
15 #include "numeric.h"
18 * The I/O factory object manages access to index storage, which is a contiguous range of blocks on
19 * a block device.
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.
24 struct io_factory {
25 struct block_device *bdev;
26 atomic_t ref_count;
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;
34 sector_t limit;
35 sector_t block_number;
36 u8 *start;
37 u8 *end;
40 #define MAX_READ_AHEAD_BLOCKS 4
43 * The buffered writer allows efficient I/O by buffering writes and committing page-sized segments
44 * to storage.
46 struct buffered_writer {
47 struct io_factory *factory;
48 struct dm_bufio_client *client;
49 struct dm_buffer *buffer;
50 sector_t limit;
51 sector_t block_number;
52 u8 *start;
53 u8 *end;
54 int error;
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)
64 int result;
65 struct io_factory *factory;
67 result = vdo_allocate(1, struct io_factory, __func__, &factory);
68 if (result != VDO_SUCCESS)
69 return result;
71 factory->bdev = bdev;
72 atomic_set_release(&factory->ref_count, 1);
74 *factory_ptr = factory;
75 return UDS_SUCCESS;
78 int uds_replace_storage(struct io_factory *factory, struct block_device *bdev)
80 factory->bdev = bdev;
81 return UDS_SUCCESS;
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)
88 vdo_free(factory);
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,
103 NULL, NULL, 0);
104 if (IS_ERR(client))
105 return -PTR_ERR(client);
107 dm_bufio_set_sector_offset(client, block_offset * SECTORS_PER_BLOCK);
108 *client_ptr = client;
109 return UDS_SUCCESS;
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)
124 if (reader == NULL)
125 return;
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);
132 vdo_free(reader);
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)
139 int result;
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)
145 return result;
147 result = vdo_allocate(1, struct buffered_reader, "buffered reader", &reader);
148 if (result != VDO_SUCCESS) {
149 dm_bufio_client_destroy(client);
150 return result;
153 *reader = (struct buffered_reader) {
154 .factory = factory,
155 .client = client,
156 .buffer = NULL,
157 .limit = block_count,
158 .block_number = 0,
159 .start = NULL,
160 .end = NULL,
163 read_ahead(reader, 0);
164 uds_get_io_factory(factory);
165 *reader_ptr = reader;
166 return UDS_SUCCESS;
169 static int position_reader(struct buffered_reader *reader, sector_t block_number,
170 off_t offset)
172 struct dm_buffer *buffer = NULL;
173 void *data;
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);
183 if (IS_ERR(data))
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;
194 return UDS_SUCCESS;
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)
207 return UDS_SUCCESS;
209 block_number = reader->block_number;
210 if (reader->end != NULL)
211 block_number++;
213 return position_reader(reader, block_number, 0);
216 int uds_read_from_buffered_reader(struct buffered_reader *reader, u8 *data,
217 size_t length)
219 int result = UDS_SUCCESS;
220 size_t chunk_size;
222 while (length > 0) {
223 result = reset_reader(reader);
224 if (result != UDS_SUCCESS)
225 return result;
227 chunk_size = min(length, bytes_remaining_in_read_buffer(reader));
228 memcpy(data, reader->end, chunk_size);
229 length -= chunk_size;
230 data += chunk_size;
231 reader->end += chunk_size;
234 return UDS_SUCCESS;
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,
242 size_t length)
244 int result = UDS_SUCCESS;
245 size_t chunk_size;
246 sector_t start_block_number = reader->block_number;
247 int start_offset = reader->end - reader->start;
249 while (length > 0) {
250 result = reset_reader(reader);
251 if (result != UDS_SUCCESS) {
252 result = UDS_CORRUPT_DATA;
253 break;
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;
259 break;
262 length -= chunk_size;
263 value += chunk_size;
264 reader->end += chunk_size;
267 if (result != UDS_SUCCESS)
268 position_reader(reader, start_block_number, start_offset);
270 return result;
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)
277 int result;
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)
283 return result;
285 result = vdo_allocate(1, struct buffered_writer, "buffered writer", &writer);
286 if (result != VDO_SUCCESS) {
287 dm_bufio_client_destroy(client);
288 return result;
291 *writer = (struct buffered_writer) {
292 .factory = factory,
293 .client = client,
294 .buffer = NULL,
295 .limit = block_count,
296 .start = NULL,
297 .end = NULL,
298 .block_number = 0,
299 .error = UDS_SUCCESS,
302 uds_get_io_factory(factory);
303 *writer_ptr = writer;
304 return UDS_SUCCESS;
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;
315 void *data;
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);
323 if (IS_ERR(data)) {
324 writer->error = -PTR_ERR(data);
325 return writer->error;
328 writer->buffer = buffer;
329 writer->start = data;
330 writer->end = data;
331 return UDS_SUCCESS;
334 static int flush_previous_buffer(struct buffered_writer *writer)
336 size_t available;
338 if (writer->buffer == NULL)
339 return writer->error;
341 if (writer->error == UDS_SUCCESS) {
342 available = get_remaining_write_space(writer);
344 if (available > 0)
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;
353 writer->end = NULL;
354 writer->block_number++;
355 return writer->error;
358 void uds_free_buffered_writer(struct buffered_writer *writer)
360 int result;
362 if (writer == NULL)
363 return;
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);
372 vdo_free(writer);
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,
380 size_t length)
382 int result = writer->error;
383 size_t chunk_size;
385 while ((length > 0) && (result == UDS_SUCCESS)) {
386 if (writer->buffer == NULL) {
387 result = prepare_next_buffer(writer);
388 continue;
391 chunk_size = min(length, get_remaining_write_space(writer));
392 if (data == NULL) {
393 memset(writer->end, 0, chunk_size);
394 } else {
395 memcpy(writer->end, data, chunk_size);
396 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);
406 return result;
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);