From 8d427f9511964b9e40db5b99072e59d3bd7f4105 Mon Sep 17 00:00:00 2001 From: Muminul Islam Date: Thu, 3 Oct 2024 11:48:58 -0700 Subject: [PATCH 1/3] atomic_bitmap: keep the byte_size in the AtomicBitmap Keeping the byte_size in the struct gives freedom to the caller to use it for any processing at their end.This field can be used by the caller in case of enlarging the bitmap. Signed-off-by: Muminul Islam --- src/bitmap/backend/atomic_bitmap.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bitmap/backend/atomic_bitmap.rs b/src/bitmap/backend/atomic_bitmap.rs index 79f023de..88bddaf2 100644 --- a/src/bitmap/backend/atomic_bitmap.rs +++ b/src/bitmap/backend/atomic_bitmap.rs @@ -18,6 +18,7 @@ use crate::mmap::NewBitmap; pub struct AtomicBitmap { map: Vec, size: usize, + byte_size: usize, page_size: NonZeroUsize, } @@ -33,6 +34,7 @@ impl AtomicBitmap { AtomicBitmap { map, size: num_pages, + byte_size, page_size, } } @@ -117,6 +119,11 @@ impl AtomicBitmap { self.size } + /// Get the size in bytes i.e how many bytes the bitmap can represent, one bit per page. + pub fn byte_size(&self) -> usize { + self.byte_size + } + /// Atomically get and reset the dirty page bitmap. pub fn get_and_reset(&self) -> Vec { self.map @@ -144,6 +151,7 @@ impl Clone for AtomicBitmap { AtomicBitmap { map, size: self.size, + byte_size: self.byte_size, page_size: self.page_size, } } From df3382a9a9b3c04f805bd63023f8b205b4facf16 Mon Sep 17 00:00:00 2001 From: Muminul Islam Date: Tue, 1 Oct 2024 12:41:38 -0700 Subject: [PATCH 2/3] atomic_bitmap: support enlarging the bitmap This patch adds the support the enlarge the atomic bitmap. Some use cases in cloud-Hypervisor needs to enlarge the bitmap on-demand. Signed-off-by: Muminul Islam --- src/bitmap/backend/atomic_bitmap.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bitmap/backend/atomic_bitmap.rs b/src/bitmap/backend/atomic_bitmap.rs index 88bddaf2..1d87d236 100644 --- a/src/bitmap/backend/atomic_bitmap.rs +++ b/src/bitmap/backend/atomic_bitmap.rs @@ -39,6 +39,15 @@ impl AtomicBitmap { } } + /// Enlarge this bitmap with enough bits to track `additional_size` additional bytes at page granularity. + /// New bits are initialized to zero. + pub fn enlarge(&mut self, additional_size: usize) { + self.byte_size += additional_size; + self.size = self.byte_size.div_ceil(self.page_size.get()); + let map_size = self.size.div_ceil(u64::BITS as usize); + self.map.resize_with(map_size, Default::default); + } + /// Is bit `n` set? Bits outside the range of the bitmap are always unset. pub fn is_bit_set(&self, index: usize) -> bool { if index < self.size { From bac5f9937cbcda4e1c2269228175fd9066b7ed1d Mon Sep 17 00:00:00 2001 From: Muminul Islam Date: Tue, 1 Oct 2024 12:42:17 -0700 Subject: [PATCH 3/3] atomic_bitmap: add test case to validate enlarge function Add one test case to validate the enlarge function of the AtomicBitmap struct. Signed-off-by: Muminul Islam --- src/bitmap/backend/atomic_bitmap.rs | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/bitmap/backend/atomic_bitmap.rs b/src/bitmap/backend/atomic_bitmap.rs index 1d87d236..b1630439 100644 --- a/src/bitmap/backend/atomic_bitmap.rs +++ b/src/bitmap/backend/atomic_bitmap.rs @@ -295,4 +295,44 @@ mod tests { let b = AtomicBitmap::new(0x800, DEFAULT_PAGE_SIZE); test_bitmap(&b); } + + #[test] + fn test_bitmap_enlarge() { + let mut b = AtomicBitmap::new(8 * 1024, DEFAULT_PAGE_SIZE); + assert_eq!(b.len(), 64); + b.set_addr_range(128, 129); + assert!(!b.is_addr_set(0)); + assert!(b.is_addr_set(128)); + assert!(b.is_addr_set(256)); + assert!(!b.is_addr_set(384)); + + b.reset_addr_range(128, 129); + assert!(!b.is_addr_set(0)); + assert!(!b.is_addr_set(128)); + assert!(!b.is_addr_set(256)); + assert!(!b.is_addr_set(384)); + b.set_addr_range(128, 129); + b.enlarge(8 * 1024); + for i in 65..128 { + assert!(!b.is_bit_set(i)); + } + assert_eq!(b.len(), 128); + assert!(!b.is_addr_set(0)); + assert!(b.is_addr_set(128)); + assert!(b.is_addr_set(256)); + assert!(!b.is_addr_set(384)); + + b.set_bit(55); + assert!(b.is_bit_set(55)); + for i in 65..128 { + b.set_bit(i); + } + for i in 65..128 { + assert!(b.is_bit_set(i)); + } + b.reset_addr_range(0, 16 * 1024); + for i in 0..128 { + assert!(!b.is_bit_set(i)); + } + } }