Skip to content

Commit 6a3ef2a

Browse files
committed
vmm: fix the size of a virtio device, backed by a block device
When a virtio device is backed by a block device, the actual size of the block device file doesn't represent the size as a virtio device. Fixes #1316 Signed-off-by: Kazuyoshi Kato <[email protected]>
1 parent 6d1c7c6 commit 6a3ef2a

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

tests/integration_tests/functional/test_drives.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55
import os
66
import platform
7+
from subprocess import run, CalledProcessError, PIPE
78

89
import pytest
910

1011
import host_tools.drive as drive_tools
1112
import host_tools.network as net_tools # pylint: disable=import-error
1213

1314

14-
def test_rescan(test_microvm_with_ssh, network_config):
15-
"""Verify that a block device rescan has guest seeing changes."""
15+
def test_rescan_file(test_microvm_with_ssh, network_config):
16+
"""Verify that rescan works with a file-backed virtio device."""
1617
test_microvm = test_microvm_with_ssh
1718
test_microvm.spawn()
1819

@@ -57,6 +58,62 @@ def test_rescan(test_microvm_with_ssh, network_config):
5758
)
5859

5960

61+
def test_rescan_dev(test_microvm_with_ssh, network_config):
62+
"""Verify that rescan works with a device-backed virtio device."""
63+
test_microvm = test_microvm_with_ssh
64+
test_microvm.spawn()
65+
session = test_microvm.api_session
66+
67+
# Set up the microVM with 1 vCPUs, 256 MiB of RAM, 0 network ifaces and
68+
# a root file system with the rw permission. The network interface is
69+
# added after we get a unique MAC and IP.
70+
test_microvm.basic_config()
71+
72+
_tap, _, _ = test_microvm_with_ssh.ssh_network_config(network_config, '1')
73+
74+
# Add a scratch block device.
75+
fs1 = drive_tools.FilesystemFile(os.path.join(test_microvm.fsfiles, 'fs1'))
76+
response = test_microvm.drive.put(
77+
drive_id='scratch',
78+
path_on_host=test_microvm.create_jailed_resource(fs1.path),
79+
is_root_device=False,
80+
is_read_only=False
81+
)
82+
assert session.is_status_no_content(response.status_code)
83+
84+
test_microvm.start()
85+
86+
ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)
87+
88+
_check_scratch_size(ssh_connection, fs1.size())
89+
90+
fs2 = drive_tools.FilesystemFile(
91+
os.path.join(test_microvm.fsfiles, 'fs2'),
92+
size=512
93+
)
94+
95+
losetup = ['losetup', '--find', '--show', fs2.path]
96+
loopback_device = None
97+
try:
98+
result = run(losetup, check=True, stdout=PIPE, stderr=PIPE)
99+
loopback_device = result.stdout.decode('utf-8').rstrip()
100+
except CalledProcessError as error:
101+
pytest.skip('failed to create a lookback device: ' +
102+
f'stdout={error.stdout}, stderr={error.stderr}')
103+
104+
try:
105+
response = test_microvm.drive.patch(
106+
drive_id='scratch',
107+
path_on_host=test_microvm.create_jailed_resource(loopback_device),
108+
)
109+
assert session.is_status_no_content(response.status_code)
110+
111+
_check_scratch_size(ssh_connection, fs2.size())
112+
finally:
113+
if loopback_device:
114+
run(['losetup', '--detach', loopback_device], check=True)
115+
116+
60117
def test_non_partuuid_boot(test_microvm_with_ssh, network_config):
61118
"""Test the output reported by blockdev when booting from /dev/vda."""
62119
test_microvm = test_microvm_with_ssh

vmm/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ mod vstate;
4747
use std::collections::HashMap;
4848
use std::fs::{metadata, File, OpenOptions};
4949
use std::io;
50+
use std::os::unix::fs::FileTypeExt;
5051
use std::os::unix::io::{AsRawFd, RawFd};
5152
use std::path::PathBuf;
5253
use std::process;
@@ -84,7 +85,7 @@ use memory_model::{GuestAddress, GuestMemory};
8485
use net_util::TapError;
8586
#[cfg(target_arch = "aarch64")]
8687
use serde_json::Value;
87-
use sys_util::{EventFd, Terminal};
88+
use sys_util::{get_blk_dev_size, EventFd, Terminal};
8889
use vmm_config::boot_source::{
8990
BootSourceConfig, BootSourceConfigError, KernelConfig, DEFAULT_KERNEL_CMDLINE,
9091
};
@@ -1525,7 +1526,12 @@ impl Vmm {
15251526
if drive_config.drive_id == *drive_id {
15261527
let metadata = metadata(&drive_config.path_on_host)
15271528
.map_err(|_| DriveError::BlockDeviceUpdateFailed)?;
1528-
let new_size = metadata.len();
1529+
let new_size = if metadata.file_type().is_block_device() {
1530+
get_blk_dev_size(&drive_config.path_on_host)
1531+
.map_err(|_| DriveError::BlockDeviceUpdateFailed)?
1532+
} else {
1533+
metadata.len()
1534+
};
15291535
if new_size % virtio::block::SECTOR_SIZE != 0 {
15301536
warn!(
15311537
"Disk size {} is not a multiple of sector size {}; \

0 commit comments

Comments
 (0)