Skip to content

Commit 0eb26a0

Browse files
committed
feat: init macos passthrough
Signed-off-by: akitaSummer <[email protected]>
1 parent 627f55b commit 0eb26a0

File tree

8 files changed

+500
-24
lines changed

8 files changed

+500
-24
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ tokio-uring = { version = "0.4.0", optional = true }
4747
tokio-test = "0.4.2"
4848
vmm-sys-util = "0.11"
4949
vm-memory = { version = "0.10", features = ["backend-mmap", "backend-bitmap"] }
50+
[target.'cfg(target_os = "macos")'.dev-dependencies]
51+
tempfile = "3.2.0"
5052

5153
[features]
5254
default = ["fusedev"]

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ pub type Result<T> = ::std::result::Result<T, Error>;
117117
pub mod abi;
118118
pub mod api;
119119

120-
#[cfg(all(any(feature = "fusedev", feature = "virtiofs"), target_os = "linux"))]
120+
// #[cfg(all(any(feature = "fusedev", feature = "virtiofs"), target_os = "linux"))]
121121
pub mod passthrough;
122122
pub mod transport;
123123

src/passthrough/inode_store.rs

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,25 @@
44
use std::collections::BTreeMap;
55
use std::sync::Arc;
66

7+
#[cfg(target_os = "linux")]
78
use super::file_handle::FileHandle;
9+
#[cfg(target_os = "macos")]
10+
use super::stat::Stat;
11+
#[cfg(target_os = "linux")]
812
use super::statx::StatExt;
9-
use super::{Inode, InodeData, InodeHandle};
13+
use super::{InoT, Inode, InodeData, InodeHandle};
1014

1115
#[derive(Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq, Debug)]
1216
/// Identify an inode in `PassthroughFs` by `InodeId`.
1317
pub struct InodeId {
14-
pub ino: libc::ino64_t,
18+
pub ino: InoT,
1519
pub dev: libc::dev_t,
20+
#[cfg(target_os = "linux")]
1621
pub mnt: u64,
1722
}
1823

1924
impl InodeId {
25+
#[cfg(target_os = "linux")]
2026
#[inline]
2127
pub(super) fn from_stat(st: &StatExt) -> Self {
2228
InodeId {
@@ -25,12 +31,22 @@ impl InodeId {
2531
mnt: st.mnt_id,
2632
}
2733
}
34+
35+
#[cfg(target_os = "macos")]
36+
#[inline]
37+
pub(super) fn from_stat(st: &Stat) -> Self {
38+
InodeId {
39+
ino: st.st.st_ino,
40+
dev: st.st.st_dev,
41+
}
42+
}
2843
}
2944

3045
#[derive(Default)]
3146
pub struct InodeStore {
3247
data: BTreeMap<Inode, Arc<InodeData>>,
3348
by_id: BTreeMap<InodeId, Inode>,
49+
#[cfg(target_os = "linux")]
3450
by_handle: BTreeMap<Arc<FileHandle>, Inode>,
3551
}
3652

@@ -41,6 +57,7 @@ impl InodeStore {
4157
/// will get lost.
4258
pub fn insert(&mut self, data: Arc<InodeData>) {
4359
self.by_id.insert(data.id, data.inode);
60+
#[cfg(target_os = "linux")]
4461
if let InodeHandle::Handle(handle) = &data.handle {
4562
self.by_handle
4663
.insert(handle.file_handle().clone(), data.inode);
@@ -59,6 +76,7 @@ impl InodeStore {
5976
}
6077

6178
if let Some(data) = data.as_ref() {
79+
#[cfg(target_os = "linux")]
6280
if let InodeHandle::Handle(handle) = &data.handle {
6381
self.by_handle.remove(handle.file_handle());
6482
}
@@ -69,6 +87,7 @@ impl InodeStore {
6987

7088
pub fn clear(&mut self) {
7189
self.data.clear();
90+
#[cfg(target_os = "linux")]
7291
self.by_handle.clear();
7392
self.by_id.clear();
7493
}
@@ -82,6 +101,7 @@ impl InodeStore {
82101
self.get(inode)
83102
}
84103

104+
#[cfg(target_os = "linux")]
85105
pub fn get_by_handle(&self, handle: &FileHandle) -> Option<&Arc<InodeData>> {
86106
let inode = self.inode_by_handle(handle)?;
87107
self.get(inode)
@@ -91,6 +111,7 @@ impl InodeStore {
91111
self.by_id.get(id)
92112
}
93113

114+
#[cfg(target_os = "linux")]
94115
pub fn inode_by_handle(&self, handle: &FileHandle) -> Option<&Inode> {
95116
self.by_handle.get(handle)
96117
}
@@ -105,8 +126,13 @@ mod test {
105126
use std::mem::MaybeUninit;
106127
use std::os::unix::io::AsRawFd;
107128
use std::sync::atomic::Ordering;
129+
#[cfg(target_os = "macos")]
130+
use tempfile::Builder;
131+
#[cfg(target_os = "linux")]
108132
use vmm_sys_util::tempfile::TempFile;
109133

134+
use stat::stat;
135+
110136
impl PartialEq for InodeData {
111137
fn eq(&self, other: &Self) -> bool {
112138
if self.inode != other.inode
@@ -117,16 +143,26 @@ mod test {
117143
return false;
118144
}
119145

146+
#[cfg(target_os = "linux")]
120147
match (&self.handle, &other.handle) {
121148
(InodeHandle::File(f1), InodeHandle::File(f2)) => f1.as_raw_fd() == f2.as_raw_fd(),
122149
(InodeHandle::Handle(h1), InodeHandle::Handle(h2)) => {
123150
h1.file_handle() == h2.file_handle()
124151
}
125152
_ => false,
126153
}
154+
155+
#[cfg(target_os = "macos")]
156+
match (&self.handle, &other.handle) {
157+
(InodeHandle::File(f1, _), InodeHandle::File(f2, _)) => {
158+
f1.as_raw_fd() == f2.as_raw_fd()
159+
}
160+
_ => false,
161+
}
127162
}
128163
}
129164

165+
#[cfg(target_os = "linux")]
130166
fn stat_fd(fd: &impl AsRawFd) -> io::Result<libc::stat64> {
131167
let mut st = MaybeUninit::<libc::stat64>::zeroed();
132168
let null_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") };
@@ -148,6 +184,7 @@ mod test {
148184
}
149185
}
150186

187+
#[cfg(target_os = "linux")]
151188
#[test]
152189
fn test_inode_store() {
153190
let mut m = InodeStore::default();
@@ -214,4 +251,65 @@ mod test {
214251
assert!(m.get(&inode2).is_none());
215252
assert!(m.get_by_id(&id2).is_none());
216253
}
254+
255+
#[cfg(target_os = "macos")]
256+
#[test]
257+
fn test_inode_store() {
258+
let mut m = InodeStore::default();
259+
let tmpfile1 = Builder::new().tempfile().unwrap();
260+
let tmpfile2 = Builder::new().tempfile().unwrap();
261+
262+
let inode1: Inode = 3;
263+
let inode2: Inode = 4;
264+
let inode_stat1 = stat(tmpfile1.as_file()).unwrap();
265+
let inode_stat2 = stat(tmpfile2.as_file()).unwrap();
266+
let id1 = InodeId::from_stat(&inode_stat1);
267+
let id2 = InodeId::from_stat(&inode_stat2);
268+
let cstr1 = CString::new(tmpfile1.path().to_string_lossy().to_string()).unwrap();
269+
let cstr2 = CString::new(tmpfile2.path().to_string_lossy().to_string()).unwrap();
270+
let file_or_handle1 = InodeHandle::File(tmpfile1.into_file(), cstr1);
271+
let file_or_handle2 = InodeHandle::File(tmpfile2.into_file(), cstr2);
272+
let data1 = InodeData::new(inode1, file_or_handle1, 2, id1, inode_stat1.st.st_mode);
273+
let data2 = InodeData::new(inode2, file_or_handle2, 2, id2, inode_stat2.st.st_mode);
274+
let data1 = Arc::new(data1);
275+
let data2 = Arc::new(data2);
276+
277+
m.insert(data1.clone());
278+
279+
// get not present key, expect none
280+
assert!(m.get(&1).is_none());
281+
282+
// get just inserted value by key, by id, by handle
283+
assert!(m.get_by_id(&InodeId::default()).is_none());
284+
assert_eq!(m.get(&inode1).unwrap(), &data1);
285+
assert_eq!(m.get_by_id(&id1).unwrap(), &data1);
286+
287+
// insert another value, and check again
288+
m.insert(data2.clone());
289+
assert!(m.get(&1).is_none());
290+
assert!(m.get_by_id(&InodeId::default()).is_none());
291+
assert_eq!(m.get(&inode1).unwrap(), &data1);
292+
assert_eq!(m.get_by_id(&id1).unwrap(), &data1);
293+
assert_eq!(m.get(&inode2).unwrap(), &data2);
294+
assert_eq!(m.get_by_id(&id2).unwrap(), &data2);
295+
296+
// remove non-present key
297+
assert!(m.remove(&1, false).is_none());
298+
299+
// remove present key, return its value
300+
assert_eq!(m.remove(&inode1, false).unwrap(), data1.clone());
301+
assert!(m.get(&inode1).is_none());
302+
assert!(m.get_by_id(&id1).is_none());
303+
assert_eq!(m.get(&inode2).unwrap(), &data2);
304+
assert_eq!(m.get_by_id(&id2).unwrap(), &data2);
305+
306+
// clear the map
307+
m.clear();
308+
assert!(m.get(&1).is_none());
309+
assert!(m.get_by_id(&InodeId::default()).is_none());
310+
assert!(m.get(&inode1).is_none());
311+
assert!(m.get_by_id(&id1).is_none());
312+
assert!(m.get(&inode2).is_none());
313+
assert!(m.get_by_id(&id2).is_none());
314+
}
217315
}
File renamed without changes.

src/passthrough/macos_sync_io.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (C) 2020 Alibaba Cloud. All rights reserved.
2+
// Copyright 2019 The Chromium OS Authors. All rights reserved.
3+
// Use of this source code is governed by a BSD-style license that can be
4+
// found in the LICENSE-BSD-3-Clause file.
5+
6+
//! Fuse passthrough file system, mirroring an existing FS hierarchy.
7+
8+
use std::ffi::{CStr, CString};
9+
use std::fs::File;
10+
use std::io;
11+
use std::mem::{self, size_of, ManuallyDrop, MaybeUninit};
12+
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
13+
use std::sync::atomic::Ordering;
14+
use std::sync::Arc;
15+
use std::time::Duration;
16+
17+
use super::*;
18+
use crate::abi::fuse_abi::{CreateIn, Opcode, FOPEN_IN_KILL_SUIDGID};
19+
#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
20+
use crate::abi::virtio_fs;
21+
use crate::api::filesystem::{
22+
Context, DirEntry, Entry, FileSystem, FsOptions, GetxattrReply, ListxattrReply, OpenOptions,
23+
SetattrValid, ZeroCopyReader, ZeroCopyWriter,
24+
};
25+
use crate::bytes_to_cstr;
26+
#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
27+
use crate::transport::FsCacheReqHandler;
28+
29+
impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {}
30+
31+
impl<S: BitmapSlice + Send + Sync> FileSystem for PassthroughFs<S> {
32+
type Inode = Inode;
33+
type Handle = Handle;
34+
35+
fn lookup(&self, _ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> {
36+
if name.to_bytes_with_nul().contains(&SLASH_ASCII) {
37+
return Err(einval());
38+
}
39+
self.do_lookup(parent, name)
40+
}
41+
}

0 commit comments

Comments
 (0)