mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
tests: Fix loop device race in create_loop_device
Move LOOP_CTL_GET_FREE + open + LOOP_CONFIGURE into the retry loop so each attempt requests a fresh free device number. Previously, a parallel test could claim the same device between GET_FREE and CONFIGURE, and retrying the same stale number would always fail with EBUSY. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
496c89c289
commit
ba889a6ec2
@@ -20,7 +20,7 @@ use std::process::{Child, Command, Stdio};
|
|||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use std::sync::{Mutex, mpsc};
|
use std::sync::{Mutex, mpsc};
|
||||||
use std::time::Duration;
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
use std::{fs, io, thread};
|
use std::{fs, io, thread};
|
||||||
|
|
||||||
use net_util::MacAddr;
|
use net_util::MacAddr;
|
||||||
@@ -7095,24 +7095,6 @@ mod common_parallel {
|
|||||||
.open(LOOP_CTL_PATH)
|
.open(LOOP_CTL_PATH)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Request a free loop device
|
|
||||||
let loop_device_number =
|
|
||||||
unsafe { libc::ioctl(loop_ctl_file.as_raw_fd(), LOOP_CTL_GET_FREE as _) };
|
|
||||||
|
|
||||||
if loop_device_number < 0 {
|
|
||||||
panic!("Couldn't find a free loop device");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create loop device path
|
|
||||||
let loop_device_path = format!("{LOOP_DEVICE_PREFIX}{loop_device_number}");
|
|
||||||
|
|
||||||
// Open loop device
|
|
||||||
let loop_device_file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.open(&loop_device_path)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Open backing file
|
// Open backing file
|
||||||
let backing_file = OpenOptions::new()
|
let backing_file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
@@ -7120,13 +7102,34 @@ mod common_parallel {
|
|||||||
.open(backing_file_path)
|
.open(backing_file_path)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let loop_config = LoopConfig {
|
// Retry the whole get free -> open -> configure sequence so that a
|
||||||
fd: backing_file.as_raw_fd() as u32,
|
// race with another parallel test claiming the same loop device
|
||||||
block_size,
|
// is resolved by requesting a new free device on each attempt.
|
||||||
..Default::default()
|
let mut loop_device_path = String::new();
|
||||||
};
|
|
||||||
|
|
||||||
for i in 0..num_retries {
|
for i in 0..num_retries {
|
||||||
|
// Request a free loop device
|
||||||
|
let loop_device_number =
|
||||||
|
unsafe { libc::ioctl(loop_ctl_file.as_raw_fd(), LOOP_CTL_GET_FREE as _) };
|
||||||
|
|
||||||
|
if loop_device_number < 0 {
|
||||||
|
panic!("Couldn't find a free loop device");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_device_path = format!("{LOOP_DEVICE_PREFIX}{loop_device_number}");
|
||||||
|
|
||||||
|
// Open loop device
|
||||||
|
let loop_device_file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.open(&loop_device_path)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let loop_config = LoopConfig {
|
||||||
|
fd: backing_file.as_raw_fd() as u32,
|
||||||
|
block_size,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let ret = unsafe {
|
let ret = unsafe {
|
||||||
libc::ioctl(
|
libc::ioctl(
|
||||||
loop_device_file.as_raw_fd(),
|
loop_device_file.as_raw_fd(),
|
||||||
@@ -7134,28 +7137,32 @@ mod common_parallel {
|
|||||||
&loop_config,
|
&loop_config,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if ret != 0 {
|
if ret == 0 {
|
||||||
if i < num_retries - 1 {
|
|
||||||
println!(
|
|
||||||
"Iteration {}: Failed to configure the loop device {}: {}",
|
|
||||||
i,
|
|
||||||
loop_device_path,
|
|
||||||
std::io::Error::last_os_error()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Failed {} times trying to configure the loop device {}: {}",
|
|
||||||
num_retries,
|
|
||||||
loop_device_path,
|
|
||||||
std::io::Error::last_os_error()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for a bit before retrying
|
if i < num_retries - 1 {
|
||||||
thread::sleep(std::time::Duration::new(5, 0));
|
println!(
|
||||||
|
"Iteration {}: Failed to configure loop device {}: {}",
|
||||||
|
i,
|
||||||
|
loop_device_path,
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
let jitter_ms = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.subsec_nanos()
|
||||||
|
% 500
|
||||||
|
+ 100;
|
||||||
|
thread::sleep(Duration::from_millis(jitter_ms as u64));
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Failed {} times trying to configure the loop device {}: {}",
|
||||||
|
num_retries,
|
||||||
|
loop_device_path,
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_device_path
|
loop_device_path
|
||||||
|
|||||||
Reference in New Issue
Block a user