Skip to content

Commit 4299e69

Browse files
committed
feat: add mac mod ut
1 parent fc1093f commit 4299e69

File tree

3 files changed

+417
-88
lines changed

3 files changed

+417
-88
lines changed

src/passthrough/macos_sync_io.rs

+157-1
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,172 @@ use crate::bytes_to_cstr;
2626
#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
2727
use crate::transport::FsCacheReqHandler;
2828

29-
impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {}
29+
impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
30+
fn open_inode(&self, inode: Inode, flags: i32) -> io::Result<File> {
31+
let data = self.inode_map.get(inode)?;
32+
if !is_safe_inode(data.mode) {
33+
Err(ebadf())
34+
} else {
35+
let new_flags = self.get_writeback_open_flags(flags);
36+
data.open_file(new_flags | libc::O_CLOEXEC)
37+
}
38+
}
39+
40+
fn do_open(
41+
&self,
42+
inode: Inode,
43+
flags: u32,
44+
fuse_flags: u32,
45+
) -> io::Result<(Option<Handle>, OpenOptions, Option<u32>)> {
46+
let file = self.open_inode(inode, flags as i32)?;
47+
48+
let data = HandleData::new(inode, file, flags);
49+
let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
50+
self.handle_map.insert(handle, data);
51+
52+
let mut opts = OpenOptions::empty();
53+
match self.cfg.cache_policy {
54+
// We only set the direct I/O option on files.
55+
CachePolicy::Never => opts.set(
56+
OpenOptions::DIRECT_IO,
57+
flags & (libc::O_DIRECTORY as u32) == 0,
58+
),
59+
CachePolicy::Metadata => {
60+
if flags & (libc::O_DIRECTORY as u32) == 0 {
61+
opts |= OpenOptions::DIRECT_IO;
62+
} else {
63+
opts |= OpenOptions::KEEP_CACHE;
64+
}
65+
}
66+
CachePolicy::Always => {
67+
opts |= OpenOptions::KEEP_CACHE;
68+
}
69+
_ => {}
70+
};
71+
72+
Ok((Some(handle), opts, None))
73+
}
74+
75+
fn do_getattr(&self, inode: Inode, handle: Option<Handle>) -> io::Result<(LibCStat, Duration)> {
76+
let st;
77+
let data = self.inode_map.get(inode).map_err(|e| {
78+
error!("fuse: do_getattr ino {} Not find err {:?}", inode, e);
79+
e
80+
})?;
81+
82+
// kernel sends 0 as handle in case of no_open, and it depends on fuse server to handle
83+
// this case correctly.
84+
if !self.no_open.load(Ordering::Relaxed) && handle.is_some() {
85+
// Safe as we just checked handle
86+
let hd = self.handle_map.get(handle.unwrap(), inode)?;
87+
st = stat(hd.get_file());
88+
} else {
89+
st = data.handle.stat();
90+
}
91+
92+
let st = st.map_err(|e| {
93+
error!("fuse: do_getattr stat failed ino {} err {:?}", inode, e);
94+
e
95+
})?;
96+
97+
Ok((st.st, self.cfg.attr_timeout))
98+
}
99+
}
30100

31101
impl<S: BitmapSlice + Send + Sync> FileSystem for PassthroughFs<S> {
32102
type Inode = Inode;
33103
type Handle = Handle;
34104

105+
fn init(&self, capable: FsOptions) -> io::Result<FsOptions> {
106+
if self.cfg.do_import {
107+
self.import()?;
108+
}
109+
110+
let mut opts = FsOptions::FILE_OPS;
111+
112+
Ok(opts)
113+
}
114+
35115
fn lookup(&self, _ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> {
36116
if name.to_bytes_with_nul().contains(&SLASH_ASCII) {
37117
return Err(einval());
38118
}
39119
self.do_lookup(parent, name)
40120
}
121+
122+
fn open(
123+
&self,
124+
_ctx: &Context,
125+
inode: Inode,
126+
flags: u32,
127+
fuse_flags: u32,
128+
) -> io::Result<(Option<Handle>, OpenOptions, Option<u32>)> {
129+
if self.no_open.load(Ordering::Relaxed) {
130+
info!("fuse: open is not supported.");
131+
Err(enosys())
132+
} else {
133+
self.do_open(inode, flags, fuse_flags)
134+
}
135+
}
136+
137+
fn create(
138+
&self,
139+
ctx: &Context,
140+
parent: Inode,
141+
name: &CStr,
142+
args: CreateIn,
143+
) -> io::Result<(Entry, Option<Handle>, OpenOptions, Option<u32>)> {
144+
self.validate_path_component(name)?;
145+
146+
let dir = self.inode_map.get(parent)?;
147+
let dir_file = dir.get_file()?;
148+
149+
let new_file = {
150+
let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?;
151+
152+
let flags = self.get_writeback_open_flags(args.flags as i32);
153+
Self::create_file_excl(&dir_file, name, flags, args.mode & !(args.umask & 0o777))?
154+
};
155+
156+
let entry = self.do_lookup(parent, name)?;
157+
let file = match new_file {
158+
// File didn't exist, now created by create_file_excl()
159+
Some(f) => f,
160+
// File exists, and args.flags doesn't contain O_EXCL. Now let's open it with
161+
// open_inode().
162+
None => {
163+
let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?;
164+
self.open_inode(entry.inode, args.flags as i32)?
165+
}
166+
};
167+
168+
let ret_handle = if !self.no_open.load(Ordering::Relaxed) {
169+
let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
170+
let data = HandleData::new(entry.inode, file, args.flags);
171+
172+
self.handle_map.insert(handle, data);
173+
Some(handle)
174+
} else {
175+
None
176+
};
177+
178+
let mut opts = OpenOptions::empty();
179+
match self.cfg.cache_policy {
180+
CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
181+
CachePolicy::Metadata => opts |= OpenOptions::DIRECT_IO,
182+
CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
183+
_ => {}
184+
};
185+
186+
Ok((entry, ret_handle, opts, None))
187+
}
188+
189+
fn getattr(
190+
&self,
191+
_ctx: &Context,
192+
inode: Inode,
193+
handle: Option<Handle>,
194+
) -> io::Result<(LibCStat, Duration)> {
195+
self.do_getattr(inode, handle)
196+
}
41197
}

0 commit comments

Comments
 (0)