I'm programming a driver in rust and I have the following C struct which I need to convert to something equivalent in Rust:
struct vfio_irq_set {
__u32 argsz;
__u32 flags;
__u32 index;
__u32 start;
__u32 count;
__u8 data[];
};
The only variable that causes me some problems is the data array. So far I have the following rust structure:
#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set {
argsz: u32,
flags: u32,
index: u32,
start: u32,
count: u32,
data: *const u8,
}
The rust code to initialize the structure and make the ioctl
call looks the following:
let irq_set: vfio_irq_set = vfio_irq_set {
argsz: (mem::size_of::<vfio_irq_set>() + mem::size_of::<RawFd>() * (MAX_INTERRUPT_VECTORS + 1) as usize) as u32,
count: interrupt_vector,
flags: VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
index: VFIO_PCI_MSIX_IRQ_INDEX as u32,
start: 0,
data: &[event_fd as u8] as *const u8,
};
if unsafe { libc::ioctl(device_fd, VFIO_DEVICE_SET_IRQS, &irq_set) } == -1 {
return Err(format!(
"failed to VFIO_DEVICE_SET_IRQS. Errno: {}",
unsafe { *libc::__errno_location() }
).into());
}
But I always get back a "failed to VFIO_DEVICE_SET_IRQS. Errno: 22"
.
Does someone have an idea on what I'm doing wrong?
In C, a struct whose last field is an array with no specified size is a dynamically typed struct. The data is present at the end of the struct with no extra level of indirection.
The Rust equivalent isn't a pointer (which has a fixed size), but a slice. Your struct would be in Rust:
#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set {
argsz: u32,
flags: u32,
index: u32,
start: u32,
count: u32,
data: [u8],
}
However those types are not really usable right now, and a more practical equivalent would be:
#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set<T: ?Sized> {
argsz: u32,
flags: u32,
index: u32,
start: u32,
count: u32,
data: T,
}
where you have to make sure that T
is a properly sized array or slice.
See also: