Alioth Code Coverage

vhost.rs0.00%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fs::File;
16use std::os::fd::AsRawFd;
17use std::path::Path;
18use std::sync::Arc;
19
20use snafu::{ResultExt, Snafu};
21
22use crate::errors::{BoxTrace, DebugTrace, trace_error};
23use crate::mem::mapped::Ram;
24use crate::mem::{self, LayoutUpdated};
25use crate::sys::vhost::{
26 MemoryMultipleRegion, MemoryRegion, VhostFeature, VirtqAddr, VirtqFile, VirtqState,
27 vhost_get_backend_features, vhost_get_features, vhost_set_backend_features, vhost_set_features,
28 vhost_set_mem_table, vhost_set_owner, vhost_set_virtq_addr, vhost_set_virtq_base,
29 vhost_set_virtq_call, vhost_set_virtq_err, vhost_set_virtq_kick, vhost_set_virtq_num,
30 vhost_vsock_set_guest_cid, vhost_vsock_set_running,
31};
32
33#[trace_error]
34#[derive(Snafu, DebugTrace)]
35#[snafu(module, visibility(pub(crate)), context(suffix(false)))]
36pub enum Error {
37 #[snafu(display("Error from OS"), context(false))]
38 System { error: std::io::Error },
39 #[snafu(display("Cannot access device {path:?}"))]
40 AccessDevice {
41 path: Box<Path>,
42 error: std::io::Error,
43 },
44 #[snafu(display("vhost backend is missing device feature {feature:#x}"))]
45 VhostMissingDeviceFeature { feature: u128 },
46 #[snafu(display("vhost-{dev} signals an error of queue {index:#x}"))]
47 VhostQueueErr { dev: &'static str, index: u16 },
48}
49
50type Result<T, E = Error> = std::result::Result<T, E>;
51
52#[derive(Debug)]
53pub struct VhostDev {
54 fd: File,
55}
56
57impl VhostDev {
58 pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
59 let fd = File::open(&path).context(error::AccessDevice {
60 path: path.as_ref(),
61 })?;
62 Ok(VhostDev { fd })
63 }
64
65 pub fn get_features(&self) -> Result<u64> {
66 let feat = unsafe { vhost_get_features(&self.fd) }?;
67 Ok(feat)
68 }
69
70 pub fn set_features(&self, val: &u64) -> Result<()> {
71 unsafe { vhost_set_features(&self.fd, val) }?;
72 Ok(())
73 }
74
75 pub fn get_backend_features(&self) -> Result<VhostFeature> {
76 let feat = unsafe { vhost_get_backend_features(&self.fd) }?;
77 Ok(VhostFeature::from_bits_retain(feat))
78 }
79
80 pub fn set_backend_features(&self, val: &VhostFeature) -> Result<()> {
81 unsafe { vhost_set_backend_features(&self.fd, &val.bits()) }?;
82 Ok(())
83 }
84
85 pub fn set_owner(&self) -> Result<()> {
86 unsafe { vhost_set_owner(&self.fd) }?;
87 Ok(())
88 }
89
90 pub fn set_virtq_num(&self, state: &VirtqState) -> Result<()> {
91 unsafe { vhost_set_virtq_num(&self.fd, state) }?;
92 Ok(())
93 }
94
95 pub fn set_virtq_addr(&self, addr: &VirtqAddr) -> Result<()> {
96 unsafe { vhost_set_virtq_addr(&self.fd, addr) }?;
97 Ok(())
98 }
99
100 pub fn set_virtq_base(&self, state: &VirtqState) -> Result<()> {
101 unsafe { vhost_set_virtq_base(&self.fd, state) }?;
102 Ok(())
103 }
104
105 pub fn set_virtq_kick(&self, file: &VirtqFile) -> Result<()> {
106 unsafe { vhost_set_virtq_kick(&self.fd, file) }?;
107 Ok(())
108 }
109
110 pub fn set_virtq_call(&self, file: &VirtqFile) -> Result<()> {
111 unsafe { vhost_set_virtq_call(&self.fd, file) }?;
112 Ok(())
113 }
114
115 pub fn set_virtq_err(&self, file: &VirtqFile) -> Result<()> {
116 unsafe { vhost_set_virtq_err(&self.fd, file) }?;
117 Ok(())
118 }
119
120 pub fn set_mem_table<const N: usize>(&self, table: &MemoryMultipleRegion<N>) -> Result<()> {
121 unsafe { vhost_set_mem_table(&self.fd, table) }?;
122 Ok(())
123 }
124
125 pub fn vsock_set_guest_cid(&self, cid: u64) -> Result<()> {
126 unsafe { vhost_vsock_set_guest_cid(&self.fd, &cid) }?;
127 Ok(())
128 }
129
130 pub fn vsock_set_running(&self, val: bool) -> Result<()> {
131 unsafe { vhost_vsock_set_running(&self.fd, &(val as _)) }?;
132 Ok(())
133 }
134}
135
136#[derive(Debug)]
137pub struct UpdateVsockMem {
138 pub dev: Arc<VhostDev>,
139}
140
141impl LayoutUpdated for UpdateVsockMem {
142 fn ram_updated(&self, ram: &Ram) -> mem::Result<()> {
143 let mut table = MemoryMultipleRegion {
144 num: 0,
145 _padding: 0,
146 regions: [MemoryRegion::default(); 64],
147 };
148 for (index, (gpa, user_mem)) in ram.iter().enumerate() {
149 table.num += 1;
150 table.regions[index].gpa = gpa;
151 table.regions[index].hva = user_mem.addr() as u64;
152 table.regions[index].size = user_mem.size();
153 }
154 let ret = self.dev.set_mem_table(&table);
155 ret.box_trace(mem::error::ChangeLayout)?;
156 log::trace!(
157 "vhost-{}: updated mem table to {:x?}",
158 self.dev.fd.as_raw_fd(),
159 &table.regions[..table.num as usize]
160 );
161 Ok(())
162 }
163}
164