Skip to content

Commit fa4471e

Browse files
jiangliubergwolf
authored andcommitted
ptfs: switch to new mount-fd implementation
Switch to new mount-fd implementation. Signed-off-by: Jiang Liu <[email protected]>
1 parent 7f3d5b7 commit fa4471e

File tree

6 files changed

+285
-329
lines changed

6 files changed

+285
-329
lines changed

src/passthrough/async_io.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ impl<S: BitmapSlice + Send + Sync + 'static> BackendFileSystem for PassthroughFs
3030
}
3131

3232
impl<'a> InodeData {
33-
async fn async_get_file(&self, mount_fds: &MountFds) -> io::Result<InodeFile<'_>> {
33+
async fn async_get_file(&self) -> io::Result<InodeFile<'_>> {
3434
// The io_uring doesn't support open_by_handle_at yet, so use sync io.
35-
self.get_file(mount_fds)
35+
self.get_file()
3636
}
3737
}
3838

src/passthrough/file_handle.rs

Lines changed: 42 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,16 @@
33
// found in the LICENSE-BSD-3-Clause file.
44

55
use std::cmp::Ordering;
6-
use std::collections::HashMap;
76
use std::ffi::CStr;
87
use std::fmt::{Debug, Formatter};
98
use std::fs::File;
109
use std::io;
1110
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
12-
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
11+
use std::sync::Arc;
1312

14-
use vmm_sys_util::{
15-
fam::{FamStruct, FamStructWrapper},
16-
generate_fam_struct_impl,
17-
};
13+
use vmm_sys_util::fam::{FamStruct, FamStructWrapper};
1814

19-
use crate::passthrough::PassthroughFs;
15+
use super::mount_fd::{MountFd, MountFds, MountId};
2016

2117
/// An arbitrary maximum size for CFileHandle::f_handle.
2218
///
@@ -64,7 +60,7 @@ pub struct CFileHandleInner {
6460
pub f_handle: __IncompleteArrayField<libc::c_char>,
6561
}
6662

67-
generate_fam_struct_impl!(
63+
vmm_sys_util::generate_fam_struct_impl!(
6864
CFileHandleInner,
6965
libc::c_char,
7066
f_handle,
@@ -230,46 +226,70 @@ impl FileHandle {
230226
handle: c_fh,
231227
})
232228
} else {
233-
let e = io::Error::last_os_error();
234-
Err(e)
229+
Err(io::Error::last_os_error())
235230
}
236231
}
232+
}
233+
234+
pub struct OpenableFileHandle {
235+
handle: Arc<FileHandle>,
236+
mount_fd: Arc<MountFd>,
237+
}
238+
239+
impl Debug for OpenableFileHandle {
240+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
241+
let fh = self.handle.handle.wrapper.as_fam_struct_ref();
242+
write!(
243+
f,
244+
"Openable file handle: mountfd {}, type {}, len {}",
245+
self.mount_fd.file().as_raw_fd(),
246+
fh.handle_type,
247+
fh.handle_bytes
248+
)
249+
}
250+
}
237251

252+
impl OpenableFileHandle {
238253
/// Create a file handle for the given file.
239254
///
240255
/// Also ensure that `mount_fds` contains a valid fd for the mount the file is on (so that
241256
/// `handle.open_with_mount_fds()` will work).
242257
///
243258
/// If `path` is empty, `reopen_dir` may be invoked to duplicate `dir` with custom
244259
/// `libc::open()` flags.
245-
pub fn from_name_at_with_mount_fds<F>(
260+
pub fn from_name_at<F>(
246261
dir_fd: RawFd,
247262
path: &CStr,
248263
mount_fds: &MountFds,
249264
reopen_dir: F,
250-
) -> io::Result<Self>
265+
) -> io::Result<OpenableFileHandle>
251266
where
252267
F: FnOnce(RawFd, libc::c_int, u32) -> io::Result<File>,
253268
{
254-
let handle = Self::from_name_at(dir_fd, path).map_err(|e| {
269+
let handle = FileHandle::from_name_at(dir_fd, path).map_err(|e| {
255270
error!("from_name_at failed error {:?}", e);
256271
e
257272
})?;
258273

259-
mount_fds.ensure_mount_point(handle.mnt_id, dir_fd, path, reopen_dir)?;
274+
let mount_fd = mount_fds
275+
.get(handle.mnt_id, reopen_dir)
276+
.map_err(|e| e.into_inner())?;
260277

261-
Ok(handle)
278+
Ok(OpenableFileHandle {
279+
handle: Arc::new(handle),
280+
mount_fd,
281+
})
262282
}
263283

264284
/// Open a file handle (low-level wrapper).
265285
///
266286
/// `mount_fd` must be an open non-`O_PATH` file descriptor for an inode on the same mount as
267287
/// the file to be opened, i.e. the mount given by `self.mnt_id`.
268-
fn open(&self, mount_fd: &impl AsRawFd, flags: libc::c_int) -> io::Result<File> {
288+
pub fn open(&self, flags: libc::c_int) -> io::Result<File> {
269289
let ret = unsafe {
270290
open_by_handle_at(
271-
mount_fd.as_raw_fd(),
272-
self.handle.wrapper.as_fam_struct_ptr(),
291+
self.mount_fd.file().as_raw_fd(),
292+
self.handle.handle.wrapper.as_fam_struct_ptr(),
273293
flags,
274294
)
275295
};
@@ -284,115 +304,12 @@ impl FileHandle {
284304
}
285305
}
286306

287-
/// Open a file handle, using the given `mount_fds` hash map.
288-
///
289-
/// Look up `self.mnt_id` in `mount_fds`, and pass the result to `self.open()`.
290-
pub fn open_with_mount_fds(
291-
&self,
292-
mount_fds: &MountFds,
293-
flags: libc::c_int,
294-
) -> io::Result<File> {
295-
let mount_fds_locked = mount_fds.get_map();
296-
let mount_file = mount_fds_locked.get(&self.mnt_id).ok_or_else(|| {
297-
error!(
298-
"open_with_mount_fds: mnt_id {:?} is not found.",
299-
&self.mnt_id
300-
);
301-
io::Error::from_raw_os_error(libc::ENODEV)
302-
})?;
303-
304-
self.open(mount_file, flags)
305-
}
306-
}
307-
308-
/// Struct to maintain <mount ID, mountpoint file> mapping for open_by_handle_at().
309-
///
310-
/// Creating a file handle only returns a mount ID; opening a file handle requires an open fd on the
311-
/// respective mount. This is a type in which we can store fds that we know are associated with a
312-
/// given mount ID, so that when opening a handle we can look it up.
313-
#[derive(Default)]
314-
pub struct MountFds {
315-
pub(crate) map: RwLock<HashMap<u64, File>>,
316-
}
317-
318-
impl MountFds {
319-
pub fn new() -> Self {
320-
MountFds::default()
321-
}
322-
323-
pub fn get_map(&self) -> RwLockReadGuard<'_, HashMap<u64, std::fs::File>> {
324-
self.map.read().unwrap()
325-
}
326-
327-
pub fn get_map_mut(&self) -> RwLockWriteGuard<'_, HashMap<u64, std::fs::File>> {
328-
self.map.write().unwrap()
307+
pub fn mount_id(&self) -> MountId {
308+
self.handle.mnt_id
329309
}
330310

331-
fn ensure_mount_point<F>(
332-
&self,
333-
mnt_id: u64,
334-
dir_fd: RawFd,
335-
path: &CStr,
336-
reopen_dir: F,
337-
) -> io::Result<()>
338-
where
339-
F: FnOnce(RawFd, libc::c_int, u32) -> io::Result<File>,
340-
{
341-
if self.get_map().contains_key(&mnt_id) {
342-
return Ok(());
343-
}
344-
345-
let (path_fd, _path_file) = if path.to_bytes().is_empty() {
346-
// `open_by_handle_at()` needs a non-`O_PATH` fd, and `dir` may be `O_PATH`, so we
347-
// have to open a new fd here
348-
// We do not know whether `dir`/`path` is a special file, though, and we must not open
349-
// special files with anything but `O_PATH`, so we have to get some `O_PATH` fd first
350-
// that we can stat to find out whether it is safe to open.
351-
// (When opening a new fd here, keep a `File` object around so the fd is closed when it
352-
// goes out of scope.)
353-
(dir_fd, None)
354-
} else {
355-
let f = PassthroughFs::<()>::open_file(
356-
dir_fd,
357-
path,
358-
libc::O_PATH | libc::O_NOFOLLOW | libc::O_CLOEXEC,
359-
0,
360-
)
361-
.map_err(|e| {
362-
error!(
363-
"from_name_at_with_mount_fds: open_file on {:?} failed error {:?}",
364-
path, e
365-
);
366-
e
367-
})?;
368-
(f.as_raw_fd(), Some(f))
369-
};
370-
371-
// liubo: TODO find mnt id
372-
// Ensure that `file` refers to an inode with the mount ID we need
373-
// if statx(&file, None)?.mnt_id != handle.mnt_id {
374-
// return Err(io::Error::from_raw_os_error(libc::EIO));
375-
// }
376-
377-
let st = PassthroughFs::<()>::stat_fd(path_fd, None)?;
378-
// Ensure that we can safely reopen `path_fd` with `O_RDONLY`
379-
let file_type = st.st_mode & libc::S_IFMT;
380-
if file_type != libc::S_IFREG && file_type != libc::S_IFDIR {
381-
error!(
382-
"from_name_at_with_mount_fds: file {:?} is special file",
383-
path
384-
);
385-
return Err(io::Error::from_raw_os_error(libc::EIO));
386-
}
387-
388-
let file = reopen_dir(
389-
path_fd,
390-
libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_CLOEXEC,
391-
st.st_mode,
392-
)?;
393-
self.get_map_mut().insert(mnt_id, file);
394-
395-
Ok(())
311+
pub fn file_handle(&self) -> &Arc<FileHandle> {
312+
&self.handle
396313
}
397314
}
398315

src/passthrough/inode_store.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ impl InodeStore {
4242
pub fn insert(&mut self, data: Arc<InodeData>) {
4343
self.by_id.insert(data.id, data.inode);
4444
if let FileOrHandle::Handle(handle) = &data.file_or_handle {
45-
self.by_handle.insert(handle.clone(), data.inode);
45+
self.by_handle
46+
.insert(handle.file_handle().clone(), data.inode);
4647
}
4748
self.data.insert(data.inode, data);
4849
}
@@ -59,7 +60,7 @@ impl InodeStore {
5960

6061
if let Some(data) = data.as_ref() {
6162
if let FileOrHandle::Handle(handle) = &data.file_or_handle {
62-
self.by_handle.remove(handle);
63+
self.by_handle.remove(handle.file_handle());
6364
}
6465
self.by_id.remove(&data.id);
6566
}
@@ -119,7 +120,9 @@ mod test {
119120
(FileOrHandle::File(f1), FileOrHandle::File(f2)) => {
120121
f1.as_raw_fd() == f2.as_raw_fd()
121122
}
122-
(FileOrHandle::Handle(h1), FileOrHandle::Handle(h2)) => h1 == h2,
123+
(FileOrHandle::Handle(h1), FileOrHandle::Handle(h2)) => {
124+
h1.file_handle() == h2.file_handle()
125+
}
123126
_ => false,
124127
}
125128
}

src/passthrough/mod.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ use std::time::Duration;
2929

3030
use vm_memory::{bitmap::BitmapSlice, ByteValued};
3131

32-
use self::file_handle::{FileHandle, MountFds};
32+
use self::file_handle::{FileHandle, OpenableFileHandle};
3333
use self::inode_store::{InodeId, InodeStore};
34+
use self::mount_fd::MountFds;
3435
use crate::abi::fuse_abi as fuse;
3536
use crate::abi::fuse_abi::Opcode;
3637
use crate::api::filesystem::Entry;
@@ -43,6 +44,7 @@ use crate::api::{
4344
mod async_io;
4445
mod file_handle;
4546
mod inode_store;
47+
mod mount_fd;
4648
mod sync_io;
4749

4850
type Inode = u64;
@@ -137,14 +139,14 @@ impl InodeStat {
137139
#[derive(Debug)]
138140
enum FileOrHandle {
139141
File(File),
140-
Handle(Arc<FileHandle>),
142+
Handle(Arc<OpenableFileHandle>),
141143
}
142144

143145
impl FileOrHandle {
144146
fn handle(&self) -> Option<&FileHandle> {
145147
match self {
146148
FileOrHandle::File(_) => None,
147-
FileOrHandle::Handle(h) => Some(h.deref()),
149+
FileOrHandle::Handle(h) => Some(h.file_handle().deref()),
148150
}
149151
}
150152
}
@@ -207,11 +209,11 @@ impl InodeData {
207209
}
208210
}
209211

210-
fn get_file(&self, mount_fds: &MountFds) -> io::Result<InodeFile<'_>> {
212+
fn get_file(&self) -> io::Result<InodeFile<'_>> {
211213
match &self.file_or_handle {
212214
FileOrHandle::File(f) => Ok(InodeFile::Ref(f)),
213215
FileOrHandle::Handle(h) => {
214-
let f = h.open_with_mount_fds(mount_fds, libc::O_PATH)?;
216+
let f = h.open(libc::O_PATH)?;
215217
Ok(InodeFile::Owned(f))
216218
}
217219
}
@@ -679,15 +681,18 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
679681
(None, Some(a)) => (cfg.entry_timeout, a),
680682
(None, None) => (cfg.entry_timeout, cfg.attr_timeout),
681683
};
684+
685+
let mount_fds = MountFds::new(None)?;
686+
682687
Ok(PassthroughFs {
683688
inode_map: InodeMap::new(),
684689
next_inode: AtomicU64::new(fuse::ROOT_ID + 1),
685690
ino_allocator: UniqueInodeGenerator::new(),
686691

687692
handle_map: HandleMap::new(),
688693
next_handle: AtomicU64::new(1),
689-
mount_fds: MountFds::new(),
690694

695+
mount_fds,
691696
proc_self_fd,
692697

693698
writeback: AtomicBool::new(false),
@@ -779,7 +784,7 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
779784
/// This function is used by Nydus blobfs
780785
pub fn readlinkat_proc_file(&self, inode: Inode) -> io::Result<PathBuf> {
781786
let data = self.inode_map.get(inode)?;
782-
let file = data.get_file(&self.mount_fds)?;
787+
let file = data.get_file()?;
783788
let pathname = CString::new(format!("{}", file.as_raw_fd()))
784789
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
785790

@@ -892,7 +897,7 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
892897
F: FnOnce(RawFd, libc::c_int, u32) -> io::Result<File>,
893898
{
894899
let handle = if use_handle {
895-
FileHandle::from_name_at_with_mount_fds(dir_fd, name, mount_fds, reopen_dir)
900+
OpenableFileHandle::from_name_at(dir_fd, name, mount_fds, reopen_dir)
896901
} else {
897902
Err(io::Error::from_raw_os_error(libc::ENOTSUP))
898903
};
@@ -936,7 +941,7 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
936941
}
937942
FileOrHandle::Handle(h) => InodeStat {
938943
stat: Self::stat_fd(dir_fd, Some(name))?,
939-
mnt_id: h.mnt_id,
944+
mnt_id: h.mount_id(),
940945
},
941946
};
942947

@@ -981,7 +986,7 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
981986
};
982987

983988
let dir = self.inode_map.get(parent)?;
984-
let dir_file = dir.get_file(&self.mount_fds)?;
989+
let dir_file = dir.get_file()?;
985990
let (file_or_handle, st, id) = Self::open_file_or_handle(
986991
self.cfg.inode_file_handles,
987992
self.cfg.enable_mntid,

0 commit comments

Comments
 (0)