mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-08 19:33:07 +00:00
base: unix: find active pages in a file
lseek(2) + SEEK_DATA/SEEK_HOLE is used to find active data in a file. The api is also effective for memfd. snapshot feature uses to traverse active pages in the memfd backed guest memory. BUG=b:215093219 TEST=cargo test -p base unix::file::tests Change-Id: I9f0eb46a568dadc94231ac437dec25c3478a7d37 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3993126 Reviewed-by: David Stevens <stevensd@chromium.org> Commit-Queue: Shin Kawamura <kawasin@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
9406b788c3
commit
985e575e66
2 changed files with 111 additions and 0 deletions
109
base/src/sys/unix/file.rs
Normal file
109
base/src/sys/unix/file.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2022 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::error;
|
||||
use crate::AsRawDescriptor;
|
||||
use crate::Error;
|
||||
use crate::Result;
|
||||
|
||||
enum LseekOption {
|
||||
Data,
|
||||
Hole,
|
||||
}
|
||||
|
||||
fn lseek(fd: &dyn AsRawDescriptor, offset: u64, option: LseekOption) -> Result<u64> {
|
||||
let whence = match option {
|
||||
LseekOption::Data => libc::SEEK_DATA,
|
||||
LseekOption::Hole => libc::SEEK_HOLE,
|
||||
};
|
||||
// safe because this doesn't modify any memory.
|
||||
let ret = unsafe { libc::lseek64(fd.as_raw_descriptor(), offset as i64, whence) };
|
||||
if ret < 0 {
|
||||
return Err(Error::last());
|
||||
}
|
||||
Ok(ret as u64)
|
||||
}
|
||||
|
||||
/// Iterator returning the offset range of data in the file.
|
||||
///
|
||||
/// This uses `lseek(2)` internally, and thus it changes the file offset.
|
||||
pub struct FileDataIterator<'a> {
|
||||
fd: &'a dyn AsRawDescriptor,
|
||||
offset: u64,
|
||||
}
|
||||
|
||||
impl<'a> FileDataIterator<'a> {
|
||||
/// Creates the [FileDataIterator]
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `fd` - the [AsRawDescriptor] of the file
|
||||
/// * `offset` - the offset to start traversing from.
|
||||
pub fn new(fd: &'a dyn AsRawDescriptor, offset: u64) -> Self {
|
||||
Self { fd, offset }
|
||||
}
|
||||
|
||||
fn find_next_data(&self) -> Result<Option<Range<u64>>> {
|
||||
let offset_data = match lseek(self.fd, self.offset, LseekOption::Data) {
|
||||
Ok(offset) => offset,
|
||||
Err(e) => {
|
||||
return match e.errno() {
|
||||
libc::ENXIO => Ok(None),
|
||||
_ => Err(e),
|
||||
}
|
||||
}
|
||||
};
|
||||
let offset_hole = lseek(self.fd, offset_data, LseekOption::Hole)?;
|
||||
|
||||
Ok(Some(offset_data..offset_hole))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FileDataIterator<'a> {
|
||||
type Item = Range<u64>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.find_next_data() {
|
||||
Ok(data_range) => {
|
||||
if let Some(ref data_range) = data_range {
|
||||
self.offset = data_range.end;
|
||||
}
|
||||
data_range
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to get data range: {:?}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::os::unix::fs::FileExt;
|
||||
|
||||
use crate::pagesize;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn file_data_iterator() {
|
||||
let file = tempfile::tempfile().unwrap();
|
||||
|
||||
file.write_at(&[1_u8], 10).unwrap();
|
||||
file.write_at(&[1_u8], 2 * pagesize() as u64).unwrap();
|
||||
file.write_at(&[1_u8], (4 * pagesize() - 1) as u64).unwrap();
|
||||
|
||||
let iter = FileDataIterator::new(&file, 0);
|
||||
|
||||
let result: Vec<Range<u64>> = iter.collect();
|
||||
assert_eq!(result.len(), 2);
|
||||
assert_eq!(result[0], 0..(pagesize() as u64));
|
||||
assert_eq!(result[1], (2 * pagesize() as u64)..(4 * pagesize() as u64));
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ mod acpi_event;
|
|||
mod capabilities;
|
||||
mod descriptor;
|
||||
mod event;
|
||||
mod file;
|
||||
mod file_flags;
|
||||
pub mod file_traits;
|
||||
mod get_filesystem_type;
|
||||
|
@ -68,6 +69,7 @@ pub use capabilities::drop_capabilities;
|
|||
pub use descriptor::*;
|
||||
pub use event::EventExt;
|
||||
pub(crate) use event::PlatformEvent;
|
||||
pub use file::FileDataIterator;
|
||||
pub use file_flags::*;
|
||||
pub use file_traits::AsRawFds;
|
||||
pub use file_traits::FileAllocate;
|
||||
|
|
Loading…
Reference in a new issue