mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Move L1 and L2 table entry helpers, division utilities and related constants from mod.rs into a dedicated util.rs submodule. Both mod.rs and metadata.rs import from util. No functional changes. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
80 lines
3.1 KiB
Rust
80 lines
3.1 KiB
Rust
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE-BSD-3-Clause file.
|
|
//
|
|
// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved.
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
|
|
|
//! Pure helper functions and constants for QCOW2 L1/L2 table entry
|
|
//! manipulation and integer arithmetic. Shared across the `qcow` submodules.
|
|
|
|
/// Nesting depth limit for disk formats that can open other disk files.
|
|
pub(crate) const MAX_NESTING_DEPTH: u32 = 10;
|
|
|
|
// bits 0-8 and 56-63 are reserved.
|
|
pub(super) const L1_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
|
|
pub(super) const L2_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
|
|
// Flags
|
|
pub(super) const ZERO_FLAG: u64 = 1 << 0;
|
|
pub(super) const COMPRESSED_FLAG: u64 = 1 << 62;
|
|
pub(super) const COMPRESSED_SECTOR_SIZE: u64 = 512;
|
|
pub(super) const CLUSTER_USED_FLAG: u64 = 1 << 63;
|
|
|
|
/// Check if L2 entry is empty (unallocated).
|
|
pub(super) fn l2_entry_is_empty(l2_entry: u64) -> bool {
|
|
l2_entry == 0
|
|
}
|
|
|
|
/// Check bit 0 - only valid for standard clusters.
|
|
pub(super) fn l2_entry_is_zero(l2_entry: u64) -> bool {
|
|
l2_entry & ZERO_FLAG != 0
|
|
}
|
|
|
|
/// Check if L2 entry refers to a compressed cluster.
|
|
pub(super) fn l2_entry_is_compressed(l2_entry: u64) -> bool {
|
|
l2_entry & COMPRESSED_FLAG != 0
|
|
}
|
|
|
|
/// Get file offset and size of compressed cluster data.
|
|
pub(super) fn l2_entry_compressed_cluster_layout(l2_entry: u64, cluster_bits: u32) -> (u64, usize) {
|
|
let compressed_size_shift = 62 - (cluster_bits - 8);
|
|
let compressed_size_mask = (1 << (cluster_bits - 8)) - 1;
|
|
let compressed_cluster_addr = l2_entry & ((1 << compressed_size_shift) - 1);
|
|
let nsectors = (l2_entry >> compressed_size_shift & compressed_size_mask) + 1;
|
|
let compressed_cluster_size = ((nsectors * COMPRESSED_SECTOR_SIZE)
|
|
- (compressed_cluster_addr & (COMPRESSED_SECTOR_SIZE - 1)))
|
|
as usize;
|
|
(compressed_cluster_addr, compressed_cluster_size)
|
|
}
|
|
|
|
/// Get file offset of standard (non-compressed) cluster.
|
|
pub(super) fn l2_entry_std_cluster_addr(l2_entry: u64) -> u64 {
|
|
l2_entry & L2_TABLE_OFFSET_MASK
|
|
}
|
|
|
|
/// Make L2 entry for standard (non-compressed) cluster.
|
|
pub(super) fn l2_entry_make_std(cluster_addr: u64) -> u64 {
|
|
(cluster_addr & L2_TABLE_OFFSET_MASK) | CLUSTER_USED_FLAG
|
|
}
|
|
|
|
/// Make L2 entry for preallocated zero cluster.
|
|
pub(super) fn l2_entry_make_zero(cluster_addr: u64) -> u64 {
|
|
(cluster_addr & L2_TABLE_OFFSET_MASK) | CLUSTER_USED_FLAG | ZERO_FLAG
|
|
}
|
|
|
|
/// Make L1 entry with optional flags.
|
|
pub(super) fn l1_entry_make(cluster_addr: u64, refcount_is_one: bool) -> u64 {
|
|
(cluster_addr & L1_TABLE_OFFSET_MASK) | (refcount_is_one as u64 * CLUSTER_USED_FLAG)
|
|
}
|
|
|
|
/// Ceiling of the division of `dividend`/`divisor`.
|
|
pub(super) fn div_round_up_u32(dividend: u32, divisor: u32) -> u32 {
|
|
dividend / divisor + u32::from(!dividend.is_multiple_of(divisor))
|
|
}
|
|
|
|
/// Ceiling of the division of `dividend`/`divisor`.
|
|
pub(super) fn div_round_up_u64(dividend: u64, divisor: u64) -> u64 {
|
|
dividend / divisor + u64::from(!dividend.is_multiple_of(divisor))
|
|
}
|