Skip to content

Commit

Permalink
implement stable unique inode for passthroughfs
Browse files Browse the repository at this point in the history
In the current passthroughfs implementation, temporary inodes are allocated and then stored in memory,
But a FORGET request causes the inode to be removed from memory, new anodes are reassigned,
resulting in the instability of the inodes of a file. this PR implements a stable inode,
Limited by the current implementation limitations of VFS, Host inode + mnt + dev needs to be controlled in 56bit,
and it is not supported beyond the range.
  • Loading branch information
zyfjeff committed May 9, 2023
1 parent 2d286b2 commit dbaee52
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ vmm-sys-util = { version = "0.10", optional = true }
vm-memory = { version = "0.9", features = ["backend-mmap"] }
virtio-queue = { version = "0.6", optional = true }
vhost = { version = "0.5", features = ["vhost-user-slave"], optional = true }
integer-encoding = "3.0.4"

[target.'cfg(target_os = "macos")'.dependencies]
core-foundation-sys = { version = ">=0.8", optional = true }
Expand Down
130 changes: 129 additions & 1 deletion src/passthrough/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::api::{
};
use crate::passthrough::inode_store::InodeStore;
use crate::BitmapSlice;
use integer_encoding::VarInt;

#[cfg(feature = "async-io")]
mod async_io;
Expand Down Expand Up @@ -86,6 +87,23 @@ impl InodeAltKey {
mnt: ist.get_mnt_id(),
}
}

#[inline]
fn encode_unique_inode(&self) -> io::Result<libc::ino64_t> {
let mut buf = [0 as u8; 8];
// Note! The order here is more important, because it is stored at the little endian,
// so we should put the large data in the low bit and the small data in the high bit,
// so that the final number is relatively small. In general, inode > mnt > dev
// example: inode=3、mnt=2、dev=1 => 0x010203,If we put the inode last, the result is 0x030201
let mut used = self.ino.encode_var(&mut buf[..]);
used = used + self.mnt.encode_var(&mut buf[used..]);
used = used + self.dev.encode_var(&mut buf[used..]);
if used > 8 {
return Err(io::ErrorKind::InvalidInput.into());
}
// varint is lettle encode
Ok(u64::from_le_bytes(buf))
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -945,7 +963,7 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
data.inode
}
None => {
let inode = self.next_inode.fetch_add(1, Ordering::Relaxed);
let inode = ids_altkey.encode_unique_inode()?;
if inode > VFS_MAX_INO {
error!("fuse: max inode number reached: {}", VFS_MAX_INO);
return Err(io::Error::new(
Expand Down Expand Up @@ -1584,4 +1602,114 @@ mod tests {

fs.destroy();
}

#[test]
fn test_encode_unique_inode() {
{
let iak = InodeAltKey {
ino: 1,
dev: 3,
mnt: 2,
};
assert_eq!(iak.encode_unique_inode().unwrap(), 0x030201);
}

{
let iak = InodeAltKey {
ino: 1,
dev: 1,
mnt: 1,
};
assert_eq!(iak.encode_unique_inode().unwrap(), 0x010101);

let iak1 = InodeAltKey {
ino: 1,
dev: 0,
mnt: 1,
};

let iak2 = InodeAltKey {
ino: 1,
dev: 1,
mnt: 0,
};

let iak3 = InodeAltKey {
ino: 0,
dev: 1,
mnt: 1,
};
assert_ne!(
iak1.encode_unique_inode().unwrap(),
iak2.encode_unique_inode().unwrap()
);
assert_ne!(
iak1.encode_unique_inode().unwrap(),
iak3.encode_unique_inode().unwrap()
);
assert_ne!(
iak2.encode_unique_inode().unwrap(),
iak3.encode_unique_inode().unwrap()
);
}

{
let iak = InodeAltKey {
ino: u32::MAX as u64, // use 5 byte
dev: 0, // use 1 byte
mnt: u8::MAX as u64, // use 2 byte
};
assert!(iak.encode_unique_inode().unwrap() <= VFS_MAX_INO);
}

{
let iak = InodeAltKey {
ino: u32::MAX as u64, // use 5 byte
dev: 0x80 - 1, // use 1 byte
mnt: 0x80 - 1, // use 1 byte
};
assert!(iak.encode_unique_inode().unwrap() <= VFS_MAX_INO);
}

{
let iak = InodeAltKey {
ino: (u32::MAX as u64) + (0x80 - 1 as u64), // use 5 + 1 byte
dev: 0x80 - 1, // use 1 byte
mnt: 0x80 - 1, // use 1 byte
};
assert!(iak.encode_unique_inode().unwrap() <= VFS_MAX_INO);
}

{
let iak1 = InodeAltKey {
ino: (u32::MAX as u64),
dev: 0,
mnt: 0,
};

let iak2 = InodeAltKey {
ino: 0,
dev: u32::MAX as u64,
mnt: 0,
};

let iak3 = InodeAltKey {
ino: 0,
dev: 0,
mnt: (u32::MAX as u64),
};
assert_ne!(
iak1.encode_unique_inode().unwrap(),
iak2.encode_unique_inode().unwrap()
);
assert_ne!(
iak2.encode_unique_inode().unwrap(),
iak3.encode_unique_inode().unwrap()
);
assert_ne!(
iak1.encode_unique_inode().unwrap(),
iak3.encode_unique_inode().unwrap()
);
}
}
}

0 comments on commit dbaee52

Please sign in to comment.