Skip to content

Commit 9df12c8

Browse files
committed
Uhyve: implement fstat and stat hypercall
1 parent 608e007 commit 9df12c8

2 files changed

Lines changed: 75 additions & 9 deletions

File tree

src/fs/uhyve.rs

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use memory_addresses::VirtAddr;
1111
use uhyve_interface::GuestPhysAddr;
1212
use uhyve_interface::v2::Hypercall;
1313
use uhyve_interface::v2::parameters::{
14-
CloseParams, GetdentParams, GetdentResult, LseekParams, OpenParams, ReadParams, UnlinkParams,
15-
WriteParams,
14+
CloseParams, FstatParams, GetdentParams, GetdentResult, LseekParams, OpenParams, ReadParams,
15+
StatKind, StatParams, StatResult, UnlinkParams, WriteParams,
1616
};
1717

1818
use crate::arch::mm::paging::virtual_to_physical;
@@ -25,6 +25,25 @@ use crate::fs::{
2525
use crate::io;
2626
use crate::uhyve::uhyve_hypercall;
2727

28+
fn fstat_hypercall(fd: i32) -> io::Result<FileAttr> {
29+
let mut attr = FileAttr::default();
30+
let mut fstat_params = FstatParams {
31+
fd,
32+
attr: GuestPhysAddr::new(
33+
virtual_to_physical(VirtAddr::from_ptr((&raw mut attr).cast::<FileAttr>()))
34+
.unwrap()
35+
.as_u64(),
36+
),
37+
ret: StatResult::None,
38+
};
39+
uhyve_hypercall(Hypercall::FileFstat(&mut fstat_params));
40+
match fstat_params.ret {
41+
StatResult::None => Err(Errno::Nosys),
42+
StatResult::Success => Ok(attr),
43+
StatResult::Error(errno) => Err(Errno::try_from(errno).unwrap()),
44+
}
45+
}
46+
2847
#[derive(Debug)]
2948
struct UhyveFileHandleInner(i32);
3049

@@ -140,6 +159,10 @@ impl ObjectInterface for UhyveFileHandle {
140159
async fn lseek(&self, offset: isize, whence: SeekWhence) -> io::Result<isize> {
141160
self.0.lock().await.lseek(offset, whence)
142161
}
162+
163+
async fn fstat(&self) -> io::Result<FileAttr> {
164+
fstat_hypercall(self.0.lock().await.0)
165+
}
143166
}
144167

145168
impl Clone for UhyveFileHandle {
@@ -189,6 +212,10 @@ impl ObjectInterface for UhyveDirectoryHandle {
189212
GetdentResult::Error(errno) => Err(Errno::try_from(errno).unwrap()),
190213
}
191214
}
215+
216+
async fn fstat(&self) -> io::Result<FileAttr> {
217+
fstat_hypercall(self.fd)
218+
}
192219
}
193220

194221
#[derive(Debug)]
@@ -208,9 +235,37 @@ impl UhyveDirectory {
208235
fn traversal_path(&self, path: &str) -> CString {
209236
let prefix = self.prefix.as_str();
210237
let prefix = prefix.strip_suffix("/").unwrap_or(prefix);
238+
if path.is_empty() {
239+
return CString::new(prefix).unwrap();
240+
}
211241
let path = [prefix, path].join("/");
212242
CString::new(path).unwrap()
213243
}
244+
245+
fn stat_hypercall(&self, path: &str, kind: StatKind) -> io::Result<FileAttr> {
246+
let path = self.traversal_path(path);
247+
let mut attr = FileAttr::default();
248+
let mut stat_params = StatParams {
249+
name: GuestPhysAddr::new(
250+
virtual_to_physical(VirtAddr::from_ptr(path.as_ptr()))
251+
.unwrap()
252+
.as_u64(),
253+
),
254+
kind,
255+
attr: GuestPhysAddr::new(
256+
virtual_to_physical(VirtAddr::from_ptr((&raw mut attr).cast::<FileAttr>()))
257+
.unwrap()
258+
.as_u64(),
259+
),
260+
ret: StatResult::None,
261+
};
262+
uhyve_hypercall(Hypercall::FileStat(&mut stat_params));
263+
match stat_params.ret {
264+
StatResult::None => Err(Errno::Nosys),
265+
StatResult::Success => Ok(attr),
266+
StatResult::Error(errno) => Err(Errno::try_from(errno).unwrap()),
267+
}
268+
}
214269
}
215270

216271
impl VfsNode for UhyveDirectory {
@@ -219,12 +274,16 @@ impl VfsNode for UhyveDirectory {
219274
NodeKind::Directory
220275
}
221276

222-
fn traverse_stat(&self, _path: &str) -> io::Result<FileAttr> {
223-
Err(Errno::Nosys)
277+
fn get_file_attributes(&self) -> io::Result<FileAttr> {
278+
self.stat_hypercall("", StatKind::Stat)
224279
}
225280

226-
fn traverse_lstat(&self, _path: &str) -> io::Result<FileAttr> {
227-
Err(Errno::Nosys)
281+
fn traverse_stat(&self, path: &str) -> io::Result<FileAttr> {
282+
self.stat_hypercall(path, StatKind::Stat)
283+
}
284+
285+
fn traverse_lstat(&self, path: &str) -> io::Result<FileAttr> {
286+
self.stat_hypercall(path, StatKind::LStat)
228287
}
229288

230289
fn traverse_open(
@@ -249,9 +308,14 @@ impl VfsNode for UhyveDirectory {
249308
let ret = open_params.ret; // circumvent packed field access
250309
match ret {
251310
// Assumption: Uhyve will never return a standard stream.
252-
ret if ret >= 0 => Ok(Arc::new(async_lock::RwLock::new(
253-
UhyveFileHandle::new(ret).into(),
254-
))),
311+
ret if ret >= 0 => {
312+
let obj = if opt.contains(OpenOption::O_DIRECTORY) {
313+
UhyveDirectoryHandle::new(ret).into()
314+
} else {
315+
UhyveFileHandle::new(ret).into()
316+
};
317+
Ok(Arc::new(async_lock::RwLock::new(obj)))
318+
}
255319
_ => Err(ret.abs().try_into().unwrap()),
256320
}
257321
}

src/uhyve.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ fn hypercall_data(hypercall: &Hypercall<'_>) -> u64 {
4949
Hypercall::FileUnlink(data) => data_addr(*data),
5050
Hypercall::FileWrite(data) => data_addr(*data),
5151
Hypercall::Getdents(data) => data_addr(*data),
52+
Hypercall::FileStat(data) => data_addr(*data),
53+
Hypercall::FileFstat(data) => data_addr(*data),
5254
Hypercall::SerialWriteBuffer(data) => data_addr(*data),
5355
Hypercall::SerialWriteByte(byte) => u64::from(*byte),
5456
h => todo!("unimplemented hypercall {h:?}"),

0 commit comments

Comments
 (0)