drm/rockchip: Don't change hdmi reference clock rate
[drm/drm-misc.git] / drivers / md / dm-vdo / indexer / chapter-index.c
blobfb1db41c794b33cd6e9826b6e6eb770448faa7ea
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright 2023 Red Hat
4 */
6 #include "chapter-index.h"
8 #include "errors.h"
9 #include "logger.h"
10 #include "memory-alloc.h"
11 #include "permassert.h"
13 #include "hash-utils.h"
14 #include "indexer.h"
16 int uds_make_open_chapter_index(struct open_chapter_index **chapter_index,
17 const struct index_geometry *geometry, u64 volume_nonce)
19 int result;
20 size_t memory_size;
21 struct open_chapter_index *index;
23 result = vdo_allocate(1, struct open_chapter_index, "open chapter index", &index);
24 if (result != VDO_SUCCESS)
25 return result;
28 * The delta index will rebalance delta lists when memory gets tight,
29 * so give the chapter index one extra page.
31 memory_size = ((geometry->index_pages_per_chapter + 1) * geometry->bytes_per_page);
32 index->geometry = geometry;
33 index->volume_nonce = volume_nonce;
34 result = uds_initialize_delta_index(&index->delta_index, 1,
35 geometry->delta_lists_per_chapter,
36 geometry->chapter_mean_delta,
37 geometry->chapter_payload_bits,
38 memory_size, 'm');
39 if (result != UDS_SUCCESS) {
40 vdo_free(index);
41 return result;
44 index->memory_size = index->delta_index.memory_size + sizeof(struct open_chapter_index);
45 *chapter_index = index;
46 return UDS_SUCCESS;
49 void uds_free_open_chapter_index(struct open_chapter_index *chapter_index)
51 if (chapter_index == NULL)
52 return;
54 uds_uninitialize_delta_index(&chapter_index->delta_index);
55 vdo_free(chapter_index);
58 /* Re-initialize an open chapter index for a new chapter. */
59 void uds_empty_open_chapter_index(struct open_chapter_index *chapter_index,
60 u64 virtual_chapter_number)
62 uds_reset_delta_index(&chapter_index->delta_index);
63 chapter_index->virtual_chapter_number = virtual_chapter_number;
66 static inline bool was_entry_found(const struct delta_index_entry *entry, u32 address)
68 return (!entry->at_end) && (entry->key == address);
71 /* Associate a record name with the record page containing its metadata. */
72 int uds_put_open_chapter_index_record(struct open_chapter_index *chapter_index,
73 const struct uds_record_name *name,
74 u32 page_number)
76 int result;
77 struct delta_index_entry entry;
78 u32 address;
79 u32 list_number;
80 const u8 *found_name;
81 bool found;
82 const struct index_geometry *geometry = chapter_index->geometry;
83 u64 chapter_number = chapter_index->virtual_chapter_number;
84 u32 record_pages = geometry->record_pages_per_chapter;
86 result = VDO_ASSERT(page_number < record_pages,
87 "Page number within chapter (%u) exceeds the maximum value %u",
88 page_number, record_pages);
89 if (result != VDO_SUCCESS)
90 return UDS_INVALID_ARGUMENT;
92 address = uds_hash_to_chapter_delta_address(name, geometry);
93 list_number = uds_hash_to_chapter_delta_list(name, geometry);
94 result = uds_get_delta_index_entry(&chapter_index->delta_index, list_number,
95 address, name->name, &entry);
96 if (result != UDS_SUCCESS)
97 return result;
99 found = was_entry_found(&entry, address);
100 result = VDO_ASSERT(!(found && entry.is_collision),
101 "Chunk appears more than once in chapter %llu",
102 (unsigned long long) chapter_number);
103 if (result != VDO_SUCCESS)
104 return UDS_BAD_STATE;
106 found_name = (found ? name->name : NULL);
107 return uds_put_delta_index_entry(&entry, address, page_number, found_name);
111 * Pack a section of an open chapter index into a chapter index page. A range of delta lists
112 * (starting with a specified list index) is copied from the open chapter index into a memory page.
113 * The number of lists copied onto the page is returned to the caller on success.
115 * @chapter_index: The open chapter index
116 * @memory: The memory page to use
117 * @first_list: The first delta list number to be copied
118 * @last_page: If true, this is the last page of the chapter index and all the remaining lists must
119 * be packed onto this page
120 * @lists_packed: The number of delta lists that were packed onto this page
122 int uds_pack_open_chapter_index_page(struct open_chapter_index *chapter_index,
123 u8 *memory, u32 first_list, bool last_page,
124 u32 *lists_packed)
126 int result;
127 struct delta_index *delta_index = &chapter_index->delta_index;
128 struct delta_index_stats stats;
129 u64 nonce = chapter_index->volume_nonce;
130 u64 chapter_number = chapter_index->virtual_chapter_number;
131 const struct index_geometry *geometry = chapter_index->geometry;
132 u32 list_count = geometry->delta_lists_per_chapter;
133 unsigned int removals = 0;
134 struct delta_index_entry entry;
135 u32 next_list;
136 s32 list_number;
138 for (;;) {
139 result = uds_pack_delta_index_page(delta_index, nonce, memory,
140 geometry->bytes_per_page,
141 chapter_number, first_list,
142 lists_packed);
143 if (result != UDS_SUCCESS)
144 return result;
146 if ((first_list + *lists_packed) == list_count) {
147 /* All lists are packed. */
148 break;
149 } else if (*lists_packed == 0) {
151 * The next delta list does not fit on a page. This delta list will be
152 * removed.
154 } else if (last_page) {
156 * This is the last page and there are lists left unpacked, but all of the
157 * remaining lists must fit on the page. Find a list that contains entries
158 * and remove the entire list. Try the first list that does not fit. If it
159 * is empty, we will select the last list that already fits and has any
160 * entries.
162 } else {
163 /* This page is done. */
164 break;
167 if (removals == 0) {
168 uds_get_delta_index_stats(delta_index, &stats);
169 vdo_log_warning("The chapter index for chapter %llu contains %llu entries with %llu collisions",
170 (unsigned long long) chapter_number,
171 (unsigned long long) stats.record_count,
172 (unsigned long long) stats.collision_count);
175 list_number = *lists_packed;
176 do {
177 if (list_number < 0)
178 return UDS_OVERFLOW;
180 next_list = first_list + list_number--;
181 result = uds_start_delta_index_search(delta_index, next_list, 0,
182 &entry);
183 if (result != UDS_SUCCESS)
184 return result;
186 result = uds_next_delta_index_entry(&entry);
187 if (result != UDS_SUCCESS)
188 return result;
189 } while (entry.at_end);
191 do {
192 result = uds_remove_delta_index_entry(&entry);
193 if (result != UDS_SUCCESS)
194 return result;
196 removals++;
197 } while (!entry.at_end);
200 if (removals > 0) {
201 vdo_log_warning("To avoid chapter index page overflow in chapter %llu, %u entries were removed from the chapter index",
202 (unsigned long long) chapter_number, removals);
205 return UDS_SUCCESS;
208 /* Make a new chapter index page, initializing it with the data from a given index_page buffer. */
209 int uds_initialize_chapter_index_page(struct delta_index_page *index_page,
210 const struct index_geometry *geometry,
211 u8 *page_buffer, u64 volume_nonce)
213 return uds_initialize_delta_index_page(index_page, volume_nonce,
214 geometry->chapter_mean_delta,
215 geometry->chapter_payload_bits,
216 page_buffer, geometry->bytes_per_page);
219 /* Validate a chapter index page read during rebuild. */
220 int uds_validate_chapter_index_page(const struct delta_index_page *index_page,
221 const struct index_geometry *geometry)
223 int result;
224 const struct delta_index *delta_index = &index_page->delta_index;
225 u32 first = index_page->lowest_list_number;
226 u32 last = index_page->highest_list_number;
227 u32 list_number;
229 /* We walk every delta list from start to finish. */
230 for (list_number = first; list_number <= last; list_number++) {
231 struct delta_index_entry entry;
233 result = uds_start_delta_index_search(delta_index, list_number - first,
234 0, &entry);
235 if (result != UDS_SUCCESS)
236 return result;
238 for (;;) {
239 result = uds_next_delta_index_entry(&entry);
240 if (result != UDS_SUCCESS) {
242 * A random bit stream is highly likely to arrive here when we go
243 * past the end of the delta list.
245 return result;
248 if (entry.at_end)
249 break;
251 /* Also make sure that the record page field contains a plausible value. */
252 if (uds_get_delta_entry_value(&entry) >=
253 geometry->record_pages_per_chapter) {
255 * Do not log this as an error. It happens in normal operation when
256 * we are doing a rebuild but haven't written the entire volume
257 * once.
259 return UDS_CORRUPT_DATA;
263 return UDS_SUCCESS;
267 * Search a chapter index page for a record name, returning the record page number that may contain
268 * the name.
270 int uds_search_chapter_index_page(struct delta_index_page *index_page,
271 const struct index_geometry *geometry,
272 const struct uds_record_name *name,
273 u16 *record_page_ptr)
275 int result;
276 struct delta_index *delta_index = &index_page->delta_index;
277 u32 address = uds_hash_to_chapter_delta_address(name, geometry);
278 u32 delta_list_number = uds_hash_to_chapter_delta_list(name, geometry);
279 u32 sub_list_number = delta_list_number - index_page->lowest_list_number;
280 struct delta_index_entry entry;
282 result = uds_get_delta_index_entry(delta_index, sub_list_number, address,
283 name->name, &entry);
284 if (result != UDS_SUCCESS)
285 return result;
287 if (was_entry_found(&entry, address))
288 *record_page_ptr = uds_get_delta_entry_value(&entry);
289 else
290 *record_page_ptr = NO_CHAPTER_INDEX_ENTRY;
292 return UDS_SUCCESS;