Use AtomicU64 for handle_ref_count
This allows us to use a read lock instead of a write on `lookup`.
Intriguingly, the corresponding call to decrease the count in `forget`
does not need a lock, thanks to Rust. So this should be a net
performance gain.
Also, panic is a handle's reference count is about to overflow.
Bug: 220386264
Test: atest AuthFsHostTest
Change-Id: Icc3ba1a3fe92431837d6cffb470688ae0883a355
diff --git a/authfs/src/fusefs.rs b/authfs/src/fusefs.rs
index 82b8501..511db68 100644
--- a/authfs/src/fusefs.rs
+++ b/authfs/src/fusefs.rs
@@ -104,7 +104,7 @@
/// stay alive until the reference count reaches zero.
///
/// Note: This is not to be confused with hardlinks, which AuthFS doesn't currently implement.
- handle_ref_count: u64,
+ handle_ref_count: AtomicU64,
/// Whether the inode is already unlinked, i.e. should be removed, once `handle_ref_count` is
/// down to zero.
@@ -113,11 +113,11 @@
impl InodeState {
fn new(entry: AuthFsEntry) -> Self {
- InodeState { entry, handle_ref_count: 0, unlinked: false }
+ InodeState { entry, handle_ref_count: AtomicU64::new(0), unlinked: false }
}
fn new_with_ref_count(entry: AuthFsEntry, handle_ref_count: u64) -> Self {
- InodeState { entry, handle_ref_count, unlinked: false }
+ InodeState { entry, handle_ref_count: AtomicU64::new(handle_ref_count), unlinked: false }
}
}
@@ -511,7 +511,7 @@
}
fn lookup(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<Entry> {
- let mut inode_table = self.inode_table.write().unwrap();
+ let inode_table = self.inode_table.read().unwrap();
// Look up the entry's inode number in parent directory.
let inode =
@@ -528,8 +528,8 @@
})?;
// Create the entry's stat if found.
- let st = handle_inode_mut_locked(
- &mut inode_table,
+ let st = handle_inode_locked(
+ &inode_table,
&inode,
|InodeState { entry, handle_ref_count, .. }| {
let st = match entry {
@@ -551,7 +551,9 @@
AccessMode::Variable(attr.mode()),
),
}?;
- *handle_ref_count += 1;
+ if handle_ref_count.fetch_add(1, Ordering::Relaxed) == u64::MAX {
+ panic!("Handle reference count overflow");
+ }
Ok(st)
},
)?;
@@ -571,15 +573,16 @@
&mut inode_table,
&inode,
|InodeState { handle_ref_count, unlinked, .. }| {
- if count > *handle_ref_count {
+ let current = handle_ref_count.get_mut();
+ if count > *current {
error!(
"Trying to decrease refcount of inode {} by {} (> current {})",
- inode, count, *handle_ref_count
+ inode, count, *current
);
panic!(); // log to logcat with error!
}
- *handle_ref_count = handle_ref_count.saturating_sub(count);
- Ok(*unlinked && *handle_ref_count == 0)
+ *current -= count;
+ Ok(*unlinked && *current == 0)
},
);