Skip to content

Commit 963e9c2

Browse files
authored
Fix find_last_non_zero_bit, and align metadata address before converting to data address. (#1188)
This PR fixes some bugs in finding base references for internal references. Prominently two bugs: 1. The way we find the last non zero bit was wrong. We used to to use `trailing_zeroes` and compare the result with the given range of the starting and ending bits. This was simply wrong. Now we do a mask first to extract the value between the starting and the ending bits, and then use `leading_zeroes`. Performance-wise, the new code has similar performnace. 2. When we convert a metadata bit (address + bit offset) back to the data address, the metadata bit needs to be the start of the metadata value. If it is the middle of the metadata value, then the computed data address will be incorrect. This PR adds `align_metadata_address`. This PR skips some tests for LOS in plans that do not use LOS.
1 parent c320cf3 commit 963e9c2

File tree

4 files changed

+289
-28
lines changed

4 files changed

+289
-28
lines changed

src/util/metadata/side_metadata/global.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,7 @@ impl SideMetadataSpec {
991991
///
992992
/// This function uses non-atomic load for the side metadata. The user needs to make sure
993993
/// that there is no other thread that is mutating the side metadata.
994+
#[allow(clippy::let_and_return)]
994995
pub unsafe fn find_prev_non_zero_value<T: MetadataValue>(
995996
&self,
996997
data_addr: Address,
@@ -1000,7 +1001,15 @@ impl SideMetadataSpec {
10001001

10011002
if self.uses_contiguous_side_metadata() {
10021003
// Contiguous side metadata
1003-
self.find_prev_non_zero_value_fast::<T>(data_addr, search_limit_bytes)
1004+
let result = self.find_prev_non_zero_value_fast::<T>(data_addr, search_limit_bytes);
1005+
#[cfg(debug_assertions)]
1006+
{
1007+
// Double check if the implementation is correct
1008+
let result2 =
1009+
self.find_prev_non_zero_value_simple::<T>(data_addr, search_limit_bytes);
1010+
assert_eq!(result, result2, "find_prev_non_zero_value_fast returned a diffrent result from the naive implementation.");
1011+
}
1012+
result
10041013
} else {
10051014
// TODO: We should be able to optimize further for this case. However, we need to be careful that the side metadata
10061015
// is not contiguous, and we need to skip to the next chunk's side metadata when we search to a different chunk.
@@ -1018,12 +1027,10 @@ impl SideMetadataSpec {
10181027
let region_bytes = 1 << self.log_bytes_in_region;
10191028
// Figure out the range that we need to search.
10201029
let start_addr = data_addr.align_down(region_bytes);
1021-
let end_addr = data_addr
1022-
.saturating_sub(search_limit_bytes)
1023-
.align_down(region_bytes);
1030+
let end_addr = data_addr.saturating_sub(search_limit_bytes) + 1usize;
10241031

10251032
let mut cursor = start_addr;
1026-
while cursor > end_addr {
1033+
while cursor >= end_addr {
10271034
// We encounter an unmapped address. Just return None.
10281035
if !cursor.is_mapped() {
10291036
return None;
@@ -1073,6 +1080,7 @@ impl SideMetadataSpec {
10731080
BitByteRange::Bytes { start, end } => {
10741081
match helpers::find_last_non_zero_bit_in_metadata_bytes(start, end) {
10751082
helpers::FindMetaBitResult::Found { addr, bit } => {
1083+
let (addr, bit) = align_metadata_address(self, addr, bit);
10761084
res = Some(contiguous_meta_address_to_address(self, addr, bit));
10771085
// Return true to abort the search. We found the bit.
10781086
true
@@ -1091,6 +1099,7 @@ impl SideMetadataSpec {
10911099
match helpers::find_last_non_zero_bit_in_metadata_bits(addr, bit_start, bit_end)
10921100
{
10931101
helpers::FindMetaBitResult::Found { addr, bit } => {
1102+
let (addr, bit) = align_metadata_address(self, addr, bit);
10941103
res = Some(contiguous_meta_address_to_address(self, addr, bit));
10951104
// Return true to abort the search. We found the bit.
10961105
true

0 commit comments

Comments
 (0)