MCPcopy Create free account
hub / github.com/cloud-hypervisor/cloud-hypervisor / grow_l1_table

Method grow_l1_table

block/src/qcow/mod.rs:949–1030  ·  view source on GitHub ↗

Grow the L1 table to accommodate at least `new_l1_size` entries. This allocates a new L1 table at file end (guaranteeing contiguity), copies existing entries, updates refcounts, and atomically switches to the new table.

(&mut self, new_l1_size: u32)

Source from the content-addressed store, hash-verified

947 /// copies existing entries, updates refcounts, and atomically switches
948 /// to the new table.
949 fn grow_l1_table(&mut self, new_l1_size: u32) -> BlockResult<()> {
950 let old_l1_size = self.header.l1_size;
951 let old_l1_offset = self.header.l1_table_offset;
952 let cluster_size = self.raw_file.cluster_size();
953
954 let new_l1_bytes = new_l1_size as u64 * size_of::<u64>() as u64;
955 let new_l1_clusters = div_round_up_u64(new_l1_bytes, cluster_size);
956
957 // Allocate contiguous clusters at file end for new L1 table
958 let file_size = self
959 .raw_file
960 .file_mut()
961 .seek(SeekFrom::End(0))
962 .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ResizeIo(e)))?;
963 let new_l1_offset = self.raw_file.cluster_address(file_size + cluster_size - 1);
964
965 // Extend file to fit all L1 clusters
966 let new_file_end = new_l1_offset + new_l1_clusters * cluster_size;
967 self.raw_file
968 .file_mut()
969 .set_len(new_file_end)
970 .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::SettingFileSize(e)))?;
971
972 // Set refcounts for the contiguous range
973 for i in 0..new_l1_clusters {
974 self.set_cluster_refcount(new_l1_offset + i * cluster_size, 1)
975 .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ResizeIo(e)))?;
976 }
977
978 let mut new_l1_data = vec![0u64; new_l1_size as usize];
979 let old_entries = self.l1_table.get_values();
980 new_l1_data[..old_entries.len()].copy_from_slice(old_entries);
981
982 for (i, l2_addr) in new_l1_data.iter_mut().enumerate() {
983 if *l2_addr != 0 && i < old_entries.len() {
984 let refcount = self
985 .refcounts
986 .get_cluster_refcount(&mut self.raw_file, *l2_addr)
987 .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::GettingRefcount(e)))?;
988 *l2_addr = l1_entry_make(*l2_addr, refcount == 1);
989 }
990 }
991
992 // Write the new L1 table to the file.
993 self.raw_file
994 .write_pointer_table_direct(new_l1_offset, new_l1_data.iter())
995 .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ResizeIo(e)))?;
996
997 self.raw_file
998 .file_mut()
999 .sync_all()
1000 .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::SyncingHeader(e)))?;
1001
1002 self.header.l1_size = new_l1_size;
1003 self.header.l1_table_offset = new_l1_offset;
1004
1005 self.raw_file
1006 .file_mut()

Callers 1

resizeMethod · 0.45

Calls 15

div_round_up_u64Function · 0.85
newFunction · 0.85
l1_entry_makeFunction · 0.85
file_mutMethod · 0.80
cluster_addressMethod · 0.80
get_valuesMethod · 0.80
iter_mutMethod · 0.80
get_cluster_refcountMethod · 0.80
iterMethod · 0.80
sync_allMethod · 0.80
cluster_sizeMethod · 0.45

Tested by

no test coverage detected