1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2023 Red Hat
6 #include "index-page-map.h"
10 #include "memory-alloc.h"
12 #include "permassert.h"
13 #include "string-utils.h"
14 #include "thread-utils.h"
16 #include "hash-utils.h"
20 * The index page map is conceptually a two-dimensional array indexed by chapter number and index
21 * page number within the chapter. Each entry contains the number of the last delta list on that
22 * index page. In order to save memory, the information for the last page in each chapter is not
23 * recorded, as it is known from the geometry.
26 static const u8 PAGE_MAP_MAGIC
[] = "ALBIPM02";
28 #define PAGE_MAP_MAGIC_LENGTH (sizeof(PAGE_MAP_MAGIC) - 1)
30 static inline u32
get_entry_count(const struct index_geometry
*geometry
)
32 return geometry
->chapters_per_volume
* (geometry
->index_pages_per_chapter
- 1);
35 int uds_make_index_page_map(const struct index_geometry
*geometry
,
36 struct index_page_map
**map_ptr
)
39 struct index_page_map
*map
;
41 result
= vdo_allocate(1, struct index_page_map
, "page map", &map
);
42 if (result
!= VDO_SUCCESS
)
45 map
->geometry
= geometry
;
46 map
->entries_per_chapter
= geometry
->index_pages_per_chapter
- 1;
47 result
= vdo_allocate(get_entry_count(geometry
), u16
, "Index Page Map Entries",
49 if (result
!= VDO_SUCCESS
) {
50 uds_free_index_page_map(map
);
58 void uds_free_index_page_map(struct index_page_map
*map
)
61 vdo_free(map
->entries
);
66 void uds_update_index_page_map(struct index_page_map
*map
, u64 virtual_chapter_number
,
67 u32 chapter_number
, u32 index_page_number
,
68 u32 delta_list_number
)
72 map
->last_update
= virtual_chapter_number
;
73 if (index_page_number
== map
->entries_per_chapter
)
76 slot
= (chapter_number
* map
->entries_per_chapter
) + index_page_number
;
77 map
->entries
[slot
] = delta_list_number
;
80 u32
uds_find_index_page_number(const struct index_page_map
*map
,
81 const struct uds_record_name
*name
, u32 chapter_number
)
83 u32 delta_list_number
= uds_hash_to_chapter_delta_list(name
, map
->geometry
);
84 u32 slot
= chapter_number
* map
->entries_per_chapter
;
87 for (page
= 0; page
< map
->entries_per_chapter
; page
++) {
88 if (delta_list_number
<= map
->entries
[slot
+ page
])
95 void uds_get_list_number_bounds(const struct index_page_map
*map
, u32 chapter_number
,
96 u32 index_page_number
, u32
*lowest_list
,
99 u32 slot
= chapter_number
* map
->entries_per_chapter
;
101 *lowest_list
= ((index_page_number
== 0) ?
102 0 : map
->entries
[slot
+ index_page_number
- 1] + 1);
103 *highest_list
= ((index_page_number
< map
->entries_per_chapter
) ?
104 map
->entries
[slot
+ index_page_number
] :
105 map
->geometry
->delta_lists_per_chapter
- 1);
108 u64
uds_compute_index_page_map_save_size(const struct index_geometry
*geometry
)
110 return PAGE_MAP_MAGIC_LENGTH
+ sizeof(u64
) + sizeof(u16
) * get_entry_count(geometry
);
113 int uds_write_index_page_map(struct index_page_map
*map
, struct buffered_writer
*writer
)
118 u64 saved_size
= uds_compute_index_page_map_save_size(map
->geometry
);
121 result
= vdo_allocate(saved_size
, u8
, "page map data", &buffer
);
122 if (result
!= VDO_SUCCESS
)
125 memcpy(buffer
, PAGE_MAP_MAGIC
, PAGE_MAP_MAGIC_LENGTH
);
126 offset
+= PAGE_MAP_MAGIC_LENGTH
;
127 encode_u64_le(buffer
, &offset
, map
->last_update
);
128 for (i
= 0; i
< get_entry_count(map
->geometry
); i
++)
129 encode_u16_le(buffer
, &offset
, map
->entries
[i
]);
131 result
= uds_write_to_buffered_writer(writer
, buffer
, offset
);
133 if (result
!= UDS_SUCCESS
)
136 return uds_flush_buffered_writer(writer
);
139 int uds_read_index_page_map(struct index_page_map
*map
, struct buffered_reader
*reader
)
142 u8 magic
[PAGE_MAP_MAGIC_LENGTH
];
145 u64 saved_size
= uds_compute_index_page_map_save_size(map
->geometry
);
148 result
= vdo_allocate(saved_size
, u8
, "page map data", &buffer
);
149 if (result
!= VDO_SUCCESS
)
152 result
= uds_read_from_buffered_reader(reader
, buffer
, saved_size
);
153 if (result
!= UDS_SUCCESS
) {
158 memcpy(&magic
, buffer
, PAGE_MAP_MAGIC_LENGTH
);
159 offset
+= PAGE_MAP_MAGIC_LENGTH
;
160 if (memcmp(magic
, PAGE_MAP_MAGIC
, PAGE_MAP_MAGIC_LENGTH
) != 0) {
162 return UDS_CORRUPT_DATA
;
165 decode_u64_le(buffer
, &offset
, &map
->last_update
);
166 for (i
= 0; i
< get_entry_count(map
->geometry
); i
++)
167 decode_u16_le(buffer
, &offset
, &map
->entries
[i
]);
170 vdo_log_debug("read index page map, last update %llu",
171 (unsigned long long) map
->last_update
);