-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement 'lookup count' tracking for Inode
#221
Conversation
Inode
75873b8
to
f26992d
Compare
Some open questions for me:
|
I think the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be helpful to document our understanding of the rules for the lookup count, maybe as a section in the module comment at the top of inode.rs
or fs.rs
.
Here's my understanding of it:
- anything that in libfuse would call
fuse_reply_entry
orfuse_reply_create
should increment the lookup countfuse_reply_entry
is valid forlink
,lookup
,mkdir
,mknod
, andsymlink
fuse_reply_create
is valid only forcreate
- for us, we don't implement
link
,symlink
, orcreate
(ormkdir
until Implement mkdir #202), so it's justlookup
andmknod
for now - every entry returned by
readdirplus
, except.
and..
, also has its lookup count incremented (which this PR needs to do) - I don't think it's explicitly stated, but lookup counts start at zero -- the kernel can't request an inode until it knows about its existence, and it can't know about its existence until it finds out from one of the operations above, which all increment the count
// Safe to remove, kernel no longer has a reference to it. | ||
trace!(ino, "removing inode from superblock"); | ||
inodes.remove(&ino); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inode
is an Arc<InodeInner>
, and so the Inode itself might live on even though we removed it from the inode map. Maybe we should add a forgotten
flag to InodeInner
or something that we can sanity check when returning inodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there somewhere you had in mind for making this check? I'm not against such a check, but I'm also not clear where we'd do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside - I think removing the Ino -> Inode
mapping as I've written at this point is wrong. There's no reason I have right now to believe other parts of our filesystem implementation won't rely on the Inode being present in this map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those implementations would be wrong, which is kinda what I mean about having another way to check. I was thinking something like we'd assert(!inode.forgotten())
any time we're about to return an inode out of inode.rs
.
There shouldn't be any direct interaction between file (or directory) handles and lookup count. The trick is that the only way to open a file (directory) handle is to call Another way to say this is that the lookup count is a mechanism for remembering which inodes the kernel knows about. Opening a file/directory handle doesn't affect which inodes the kernel knows about, since it already knew about the one it opened. |
Signed-off-by: Daniel Carl Jones <[email protected]>
Signed-off-by: Daniel Carl Jones <[email protected]>
Signed-off-by: Daniel Carl Jones <[email protected]>
fe62ac3
to
6321a53
Compare
Signed-off-by: Daniel Carl Jones <[email protected]>
6321a53
to
82a12ae
Compare
Signed-off-by: Daniel Carl Jones <[email protected]>
@@ -1,3 +1,31 @@ | |||
//! File system types and operations, not relying on our FUSE library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
general nit on this comment: we've been roughly trying to wrap at at 120 chars wherever we can (which is what our rustfmt config is set to, but it doesn't affect comments).
//! File system types and operations, not relying on our FUSE library. | ||
//! | ||
//! **Note:** this abstraction is not intended to abstract FUSE itself, | ||
//! only allow us to run tests without FUSE in the loop. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//! only allow us to run tests without FUSE in the loop. | |
//! only allow us to run tests without a real FUSE device in the loop. |
//! #### Counting references to [Inode] | ||
//! | ||
//! One of the responsibilities of [S3Filesystem] is to track the _lookup count_. | ||
//! Lookup count is a FUSE concept and tracks the number of times we provide a reference to an [InodeNo] to the FUSE driver, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//! Lookup count is a FUSE concept and tracks the number of times we provide a reference to an [InodeNo] to the FUSE driver, | |
//! Lookup count is a FUSE concept and tracks the number of times we provide a reference to an [InodeNo] to the kernel, |
//! | ||
//! One of the responsibilities of [S3Filesystem] is to track the _lookup count_. | ||
//! Lookup count is a FUSE concept and tracks the number of times we provide a reference to an [InodeNo] to the FUSE driver, | ||
//! ensuring that we never delete an [Inode] that may be references in the future by the FUSE driver. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//! ensuring that we never delete an [Inode] that may be references in the future by the FUSE driver. | |
//! ensuring that we never forget about an [InodeNo] that may be referenced in the future by the kernel. |
//! One of the responsibilities of [S3Filesystem] is to track the _lookup count_. | ||
//! Lookup count is a FUSE concept and tracks the number of times we provide a reference to an [InodeNo] to the FUSE driver, | ||
//! ensuring that we never delete an [Inode] that may be references in the future by the FUSE driver. | ||
//! Note - this should not be confused with any counting of references to an [Inode] from its parent or a [FileHandle]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//! Note - this should not be confused with any counting of references to an [Inode] from its parent or a [FileHandle]. | |
//! This should not be confused with any counting of references to an [Inode] from its parent or a [FileHandle]. |
//! Some operations will not return a new [InodeNo] but rather one the FUSE driver already knows about. | ||
//! `open` is one such case since FUSE already provides the [InodeNo] as an argument when it calls open. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite the intent -- any operation that takes an InodeNo as input doesn't need to change the lookup count of that InodeNo
.
pub async fn readdir<R: DirectoryReplier>( | ||
&self, | ||
parent: InodeNo, | ||
fh: u64, | ||
offset: i64, | ||
plus: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
plus: bool, | |
inc_lookup_count: bool, |
//! `fuser`-specific bindings, mostly wrapping the generic filesystem code in [crate::fs]. | ||
//! | ||
//! Note that the purpose of this module is not necessarily to abstract away FUSE from a FileSystem, | ||
//! but instead to provide a thin wrapper between the `fuser` library and our filesystem handlers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for testing purposes
@@ -39,6 +39,8 @@ use crate::sync::{Arc, Mutex, RwLock}; | |||
pub type InodeNo = u64; | |||
|
|||
pub const ROOT_INODE_NO: InodeNo = 1; | |||
/// Starts at zero, as it tracks references Kernel has to the [Inode]. It's zero until returned in a FUSE reply. | |||
const DEFAULT_LOOKUP_COUNT: u64 = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const DEFAULT_LOOKUP_COUNT: u64 = 0; | |
const INITIAL_LOOKUP_COUNT: u64 = 0; |
} | ||
Some(inode) => { | ||
let lookup_count = inode.dec_lookup_count(n); | ||
if lookup_count < 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's unsigned, so
if lookup_count < 1 { | |
if lookup_count == 0 { |
@@ -97,6 +100,30 @@ impl Superblock { | |||
Self { inner: Arc::new(inner) } | |||
} | |||
|
|||
/// The kernel tells us when it removes a reference to an [InodeNo] from its internal caches via a forget call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why were we not implementing forget earlier? Is it due to kernel caching?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It wasn't a priority for us - during alpha, it did not feel essential to cleanup the superblock list of Inodes.
Caching doesn't come into why we're implementing forget I don't think, but it may (IDK) influence when the kernel is telling us its forgotten about a particular Inode.
Superseded by #359 |
Early draft of tracking
lookup_count
, so that we know when we can drop from the superblock.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and I agree to the terms of the Developer Certificate of Origin (DCO).