Skip to content

Commit b48bea7

Browse files
jiangliubergwolf
authored andcommitted
ptfs: optimize implementation of do_lookup()
Optimize implementation of do_lookup() by: - use statx() instead of fsstat64() when possible to get stat with mount id - create openable handle on demand, avoid unnecessary operations - remove InodeStat, using StatExt instead - remove function stat() and open_proc_file() Signed-off-by: Jiang Liu <[email protected]>
1 parent 336eba4 commit b48bea7

File tree

5 files changed

+144
-246
lines changed

5 files changed

+144
-246
lines changed

src/passthrough/file_handle.rs

Lines changed: 29 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::sync::Arc;
1313

1414
use vmm_sys_util::fam::{FamStruct, FamStructWrapper};
1515

16-
use super::mount_fd::{MountFd, MountFds, MountId};
17-
use super::util::enosys;
16+
use super::mount_fd::{MPRResult, MountFd, MountFds, MountId};
17+
use crate::api::EMPTY_CSTR;
1818

1919
/// An arbitrary maximum size for CFileHandle::f_handle.
2020
///
@@ -243,6 +243,33 @@ impl FileHandle {
243243
handle: c_fh,
244244
}))
245245
}
246+
247+
/// Create a file handle from a `fd`.
248+
/// This is a wrapper around `from_name_at()` and so has the same interface.
249+
pub fn from_fd(fd: &impl AsRawFd) -> io::Result<Option<Self>> {
250+
// Safe because this is a constant value and a valid C string.
251+
let empty_path = unsafe { CStr::from_bytes_with_nul_unchecked(EMPTY_CSTR) };
252+
Self::from_name_at(fd, empty_path)
253+
}
254+
255+
/// Return an openable copy of the file handle by ensuring that `mount_fd` contains a valid fd
256+
/// for the mount the file handle is for.
257+
///
258+
/// `reopen_fd` will be invoked to duplicate an `O_PATH` fd with custom `libc::open()` flags.
259+
pub fn into_openable<F>(
260+
self,
261+
mount_fds: &MountFds,
262+
reopen_fd: F,
263+
) -> MPRResult<OpenableFileHandle>
264+
where
265+
F: FnOnce(RawFd, libc::c_int, u32) -> io::Result<File>,
266+
{
267+
let mount_fd = mount_fds.get(self.mnt_id, reopen_fd)?;
268+
Ok(OpenableFileHandle {
269+
handle: Arc::new(self),
270+
mount_fd,
271+
})
272+
}
246273
}
247274

248275
pub struct OpenableFileHandle {
@@ -264,39 +291,6 @@ impl Debug for OpenableFileHandle {
264291
}
265292

266293
impl OpenableFileHandle {
267-
/// Create a file handle for the given file.
268-
///
269-
/// Also ensure that `mount_fds` contains a valid fd for the mount the file is on (so that
270-
/// `handle.open_with_mount_fds()` will work).
271-
///
272-
/// If `path` is empty, `reopen_dir` may be invoked to duplicate `dir` with custom
273-
/// `libc::open()` flags.
274-
pub fn from_name_at<F>(
275-
dir_fd: &impl AsRawFd,
276-
path: &CStr,
277-
mount_fds: &MountFds,
278-
reopen_dir: F,
279-
) -> io::Result<OpenableFileHandle>
280-
where
281-
F: FnOnce(RawFd, libc::c_int, u32) -> io::Result<File>,
282-
{
283-
let handle = FileHandle::from_name_at(dir_fd, path)
284-
.map_err(|e| {
285-
error!("from_name_at failed error {:?}", e);
286-
e
287-
})?
288-
.ok_or_else(enosys)?;
289-
290-
let mount_fd = mount_fds
291-
.get(handle.mnt_id, reopen_dir)
292-
.map_err(|e| e.into_inner())?;
293-
294-
Ok(OpenableFileHandle {
295-
handle: Arc::new(handle),
296-
mount_fd,
297-
})
298-
}
299-
300294
/// Open a file from an openable file handle.
301295
pub fn open(&self, flags: libc::c_int) -> io::Result<File> {
302296
let ret = unsafe {
@@ -317,10 +311,6 @@ impl OpenableFileHandle {
317311
}
318312
}
319313

320-
pub fn mount_id(&self) -> MountId {
321-
self.handle.mnt_id
322-
}
323-
324314
pub fn file_handle(&self) -> &Arc<FileHandle> {
325315
&self.handle
326316
}
@@ -443,29 +433,4 @@ mod tests {
443433
0
444434
);
445435
}
446-
447-
#[test]
448-
fn test_openable_file_handle() {
449-
let uid = getuid();
450-
if !uid.is_root() {
451-
return;
452-
}
453-
454-
let topdir = env!("CARGO_MANIFEST_DIR");
455-
let dir = File::open(topdir).unwrap();
456-
let filename = CString::new("build.rs").unwrap();
457-
let mount_fds = MountFds::new(None).unwrap();
458-
459-
let file_handle =
460-
OpenableFileHandle::from_name_at(&dir, &filename, &mount_fds, |_fd, _flags, _mode| {
461-
File::open(topdir)
462-
})
463-
.unwrap();
464-
assert_eq!(file_handle.handle.mnt_id, file_handle.mount_id());
465-
466-
let mut file = file_handle.open(libc::O_RDONLY).unwrap();
467-
let mut buffer = [0u8; 1024];
468-
let res = file.read(&mut buffer).unwrap();
469-
assert!(res > 0);
470-
}
471436
}

src/passthrough/inode_store.rs

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::collections::BTreeMap;
55
use std::sync::Arc;
66

77
use super::file_handle::FileHandle;
8-
use super::{Inode, InodeData, InodeHandle, InodeStat};
8+
use super::statx::StatExt;
9+
use super::{Inode, InodeData, InodeHandle};
910

1011
#[derive(Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq, Debug)]
1112
/// Identify an inode in `PassthroughFs` by `InodeId`.
@@ -17,12 +18,11 @@ pub struct InodeId {
1718

1819
impl InodeId {
1920
#[inline]
20-
pub(super) fn from_stat(ist: &InodeStat) -> Self {
21-
let st = ist.get_stat();
21+
pub(super) fn from_stat(st: &StatExt) -> Self {
2222
InodeId {
23-
ino: st.st_ino,
24-
dev: st.st_dev,
25-
mnt: ist.get_mnt_id(),
23+
ino: st.st.st_ino,
24+
dev: st.st.st_dev,
25+
mnt: st.mnt_id,
2626
}
2727
}
2828
}
@@ -103,7 +103,7 @@ mod test {
103103

104104
use std::ffi::CStr;
105105
use std::mem::MaybeUninit;
106-
use std::os::unix::io::{AsRawFd, RawFd};
106+
use std::os::unix::io::AsRawFd;
107107
use std::sync::atomic::Ordering;
108108
use vmm_sys_util::tempfile::TempFile;
109109

@@ -127,14 +127,14 @@ mod test {
127127
}
128128
}
129129

130-
fn stat_fd(fd: RawFd) -> io::Result<libc::stat64> {
130+
fn stat_fd(fd: &impl AsRawFd) -> io::Result<libc::stat64> {
131131
let mut st = MaybeUninit::<libc::stat64>::zeroed();
132132
let null_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") };
133133

134134
// Safe because the kernel will only write data in `st` and we check the return value.
135135
let res = unsafe {
136136
libc::fstatat64(
137-
fd,
137+
fd.as_raw_fd(),
138138
null_path.as_ptr(),
139139
st.as_mut_ptr(),
140140
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
@@ -156,32 +156,20 @@ mod test {
156156

157157
let inode1: Inode = 3;
158158
let inode2: Inode = 4;
159-
let inode_stat1 = InodeStat {
160-
stat: stat_fd(tmpfile1.as_file().as_raw_fd()).unwrap(),
159+
let inode_stat1 = StatExt {
160+
st: stat_fd(tmpfile1.as_file()).unwrap(),
161161
mnt_id: 0,
162162
};
163-
let inode_stat2 = InodeStat {
164-
stat: stat_fd(tmpfile2.as_file().as_raw_fd()).unwrap(),
163+
let inode_stat2 = StatExt {
164+
st: stat_fd(tmpfile2.as_file()).unwrap(),
165165
mnt_id: 0,
166166
};
167167
let id1 = InodeId::from_stat(&inode_stat1);
168168
let id2 = InodeId::from_stat(&inode_stat2);
169169
let file_or_handle1 = InodeHandle::File(tmpfile1.into_file());
170170
let file_or_handle2 = InodeHandle::File(tmpfile2.into_file());
171-
let data1 = InodeData::new(
172-
inode1,
173-
file_or_handle1,
174-
2,
175-
id1,
176-
inode_stat1.get_stat().st_mode,
177-
);
178-
let data2 = InodeData::new(
179-
inode2,
180-
file_or_handle2,
181-
2,
182-
id2,
183-
inode_stat2.get_stat().st_mode,
184-
);
171+
let data1 = InodeData::new(inode1, file_or_handle1, 2, id1, inode_stat1.st.st_mode);
172+
let data2 = InodeData::new(inode2, file_or_handle2, 2, id2, inode_stat2.st.st_mode);
185173
let data1 = Arc::new(data1);
186174
let data2 = Arc::new(data2);
187175

0 commit comments

Comments
 (0)