mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 18:20:34 +00:00
devices: block: add block_size option for disks
This allows overriding the default logical block size (512 bytes) with other values, such as 4096 for 4K block size disks. BUG=chromium:942700 TEST=crosvm run -r vm_rootfs,block_size=4096 vm_kernel TEST=verify block size with lsblk --output-all Change-Id: Ia6db05f369a76557a2afb8b48b5cc2b66cf84b01 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1954220 Reviewed-by: Zach Reizner <zachr@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
84be74727c
commit
2767223fdb
4 changed files with 49 additions and 11 deletions
|
@ -463,15 +463,16 @@ pub struct Block {
|
|||
read_only: bool,
|
||||
sparse: bool,
|
||||
seg_max: u32,
|
||||
block_size: u32,
|
||||
control_socket: Option<DiskControlResponseSocket>,
|
||||
}
|
||||
|
||||
fn build_config_space(disk_size: u64, seg_max: u32) -> virtio_blk_config {
|
||||
fn build_config_space(disk_size: u64, seg_max: u32, block_size: u32) -> virtio_blk_config {
|
||||
virtio_blk_config {
|
||||
// If the image is not a multiple of the sector size, the tail bits are not exposed.
|
||||
capacity: Le64::from(disk_size >> SECTOR_SHIFT),
|
||||
seg_max: Le32::from(seg_max),
|
||||
blk_size: Le32::from(SECTOR_SIZE as u32),
|
||||
blk_size: Le32::from(block_size),
|
||||
max_discard_sectors: Le32::from(MAX_DISCARD_SECTORS),
|
||||
discard_sector_alignment: Le32::from(DISCARD_SECTOR_ALIGNMENT),
|
||||
max_write_zeroes_sectors: Le32::from(MAX_WRITE_ZEROES_SECTORS),
|
||||
|
@ -488,14 +489,22 @@ impl Block {
|
|||
disk_image: Box<dyn DiskFile>,
|
||||
read_only: bool,
|
||||
sparse: bool,
|
||||
block_size: u32,
|
||||
control_socket: Option<DiskControlResponseSocket>,
|
||||
) -> SysResult<Block> {
|
||||
if block_size % SECTOR_SIZE as u32 != 0 {
|
||||
error!(
|
||||
"Block size {} is not a multiple of {}.",
|
||||
block_size, SECTOR_SIZE,
|
||||
);
|
||||
return Err(SysError::new(libc::EINVAL));
|
||||
}
|
||||
let disk_size = disk_image.get_len()?;
|
||||
if disk_size % SECTOR_SIZE != 0 {
|
||||
if disk_size % block_size as u64 != 0 {
|
||||
warn!(
|
||||
"Disk size {} is not a multiple of sector size {}; \
|
||||
"Disk size {} is not a multiple of block size {}; \
|
||||
the remainder will not be visible to the guest.",
|
||||
disk_size, SECTOR_SIZE
|
||||
disk_size, block_size,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -528,6 +537,7 @@ impl Block {
|
|||
read_only,
|
||||
sparse,
|
||||
seg_max,
|
||||
block_size,
|
||||
control_socket,
|
||||
})
|
||||
}
|
||||
|
@ -716,7 +726,7 @@ impl VirtioDevice for Block {
|
|||
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
||||
let config_space = {
|
||||
let disk_size = self.disk_size.lock();
|
||||
build_config_space(*disk_size, self.seg_max)
|
||||
build_config_space(*disk_size, self.seg_max, self.block_size)
|
||||
};
|
||||
copy_config(data, 0, config_space.as_slice(), offset);
|
||||
}
|
||||
|
@ -795,7 +805,7 @@ mod tests {
|
|||
let f = File::create(&path).unwrap();
|
||||
f.set_len(0x1000).unwrap();
|
||||
|
||||
let b = Block::new(Box::new(f), true, false, None).unwrap();
|
||||
let b = Block::new(Box::new(f), true, false, 512, None).unwrap();
|
||||
let mut num_sectors = [0u8; 4];
|
||||
b.read_config(0, &mut num_sectors);
|
||||
// size is 0x1000, so num_sectors is 8 (4096/512).
|
||||
|
@ -806,6 +816,21 @@ mod tests {
|
|||
assert_eq!([0x00, 0x00, 0x00, 0x00], msw_sectors);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_block_size() {
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
let mut path = tempdir.path().to_owned();
|
||||
path.push("disk_image");
|
||||
let f = File::create(&path).unwrap();
|
||||
f.set_len(0x1000).unwrap();
|
||||
|
||||
let b = Block::new(Box::new(f), true, false, 4096, None).unwrap();
|
||||
let mut blk_size = [0u8; 4];
|
||||
b.read_config(20, &mut blk_size);
|
||||
// blk_size should be 4096 (0x1000).
|
||||
assert_eq!([0x00, 0x10, 0x00, 0x00], blk_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_features() {
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
|
@ -815,7 +840,7 @@ mod tests {
|
|||
// read-write block device
|
||||
{
|
||||
let f = File::create(&path).unwrap();
|
||||
let b = Block::new(Box::new(f), false, true, None).unwrap();
|
||||
let b = Block::new(Box::new(f), false, true, 512, None).unwrap();
|
||||
// writable device should set VIRTIO_BLK_F_FLUSH + VIRTIO_BLK_F_DISCARD
|
||||
// + VIRTIO_BLK_F_WRITE_ZEROES + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE
|
||||
// + VIRTIO_BLK_F_SEG_MAX
|
||||
|
@ -825,7 +850,7 @@ mod tests {
|
|||
// read-write block device, non-sparse
|
||||
{
|
||||
let f = File::create(&path).unwrap();
|
||||
let b = Block::new(Box::new(f), false, false, None).unwrap();
|
||||
let b = Block::new(Box::new(f), false, false, 512, None).unwrap();
|
||||
// writable device should set VIRTIO_BLK_F_FLUSH
|
||||
// + VIRTIO_BLK_F_WRITE_ZEROES + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE
|
||||
// + VIRTIO_BLK_F_SEG_MAX
|
||||
|
@ -835,7 +860,7 @@ mod tests {
|
|||
// read-only block device
|
||||
{
|
||||
let f = File::create(&path).unwrap();
|
||||
let b = Block::new(Box::new(f), true, true, None).unwrap();
|
||||
let b = Block::new(Box::new(f), true, true, 512, None).unwrap();
|
||||
// read-only device should set VIRTIO_BLK_F_FLUSH and VIRTIO_BLK_F_RO
|
||||
// + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE + VIRTIO_BLK_F_SEG_MAX
|
||||
assert_eq!(0x100000264, b.features());
|
||||
|
|
|
@ -39,6 +39,7 @@ pub struct DiskOption {
|
|||
pub path: PathBuf,
|
||||
pub read_only: bool,
|
||||
pub sparse: bool,
|
||||
pub block_size: u32,
|
||||
}
|
||||
|
||||
/// A bind mount for directories in the plugin process.
|
||||
|
|
|
@ -386,6 +386,7 @@ fn create_block_device(
|
|||
disk_file,
|
||||
disk.read_only,
|
||||
disk.sparse,
|
||||
disk.block_size,
|
||||
Some(disk_device_socket),
|
||||
)
|
||||
.map_err(Error::BlockDeviceNew)?;
|
||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -378,6 +378,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
|
|||
path: disk_path,
|
||||
read_only,
|
||||
sparse: true,
|
||||
block_size: 512,
|
||||
};
|
||||
|
||||
for opt in components {
|
||||
|
@ -399,6 +400,14 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
|
|||
})?;
|
||||
disk.sparse = sparse;
|
||||
}
|
||||
"block_size" => {
|
||||
let block_size =
|
||||
value.parse().map_err(|_| argument::Error::InvalidValue {
|
||||
value: value.to_owned(),
|
||||
expected: "`block_size` must be an integer",
|
||||
})?;
|
||||
disk.block_size = block_size;
|
||||
}
|
||||
_ => {
|
||||
return Err(argument::Error::InvalidValue {
|
||||
value: kind.to_owned(),
|
||||
|
@ -423,6 +432,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
|
|||
path: disk_path,
|
||||
read_only: !name.starts_with("rw"),
|
||||
sparse: false,
|
||||
block_size: sys_util::pagesize() as u32,
|
||||
});
|
||||
}
|
||||
"host_ip" => {
|
||||
|
@ -893,7 +903,8 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
|
|||
See --disk for valid options."),
|
||||
Argument::short_value('d', "disk", "PATH[,key=value[,key=value[,...]]", "Path to a disk image followed by optional comma-separated options.
|
||||
Valid keys:
|
||||
sparse=BOOL - Indicates whether the disk should support the discard operation (default: true)"),
|
||||
sparse=BOOL - Indicates whether the disk should support the discard operation (default: true)
|
||||
block_size=BYTES - Set the reported block size of the disk (default: 512)"),
|
||||
Argument::value("qcow", "PATH", "Path to a qcow2 disk image. (Deprecated; use --disk instead.)"),
|
||||
Argument::value("rwdisk", "PATH[,key=value[,key=value[,...]]", "Path to a writable disk image followed by optional comma-separated options.
|
||||
See --disk for valid options."),
|
||||
|
|
Loading…
Reference in a new issue