Dir::scope() was declared as taking &'a self, which tied the returned
PinInit's lifetime to the Dir. This prevented using scope() with a
locally-created Dir:

    let dir = Dir::lookup(...).unwrap_or_else(Dir::empty);
    let scope = dir.scope(...);  // Error: returns value referencing local

The borrow was unnecessary since scoped_dir() internally clones the
Arc<Entry>. Fix this by cloning self.0 before the closure, allowing the
closure to capture the cloned value via move instead of borrowing self.

This also removes the now-unused scoped_dir() helper method, inlining
its logic directly into scope().

Signed-off-by: Timur Tabi <[email protected]>
---
 rust/kernel/debugfs.rs | 41 +++++++++++++++++------------------------
 1 file changed, 17 insertions(+), 24 deletions(-)

diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index b0cfe22982d6..35f9cbb261e7 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -397,27 +397,6 @@ pub fn write_callback_file<'a, T, E: 'a, W>(
         self.create_file(name, data, file_ops)
     }
 
-    // While this function is safe, it is intentionally not public because 
it's a bit of a
-    // footgun.
-    //
-    // Unless you also extract the `entry` later and schedule it for `Drop` at 
the appropriate
-    // time, a `ScopedDir` with a `Dir` parent will never be deleted.
-    fn scoped_dir<'data>(&self, name: &CStr) -> ScopedDir<'data, 'static> {
-        #[cfg(CONFIG_DEBUG_FS)]
-        {
-            let parent_entry = match &self.0 {
-                None => return ScopedDir::empty(),
-                Some(entry) => entry.clone(),
-            };
-            ScopedDir {
-                entry: ManuallyDrop::new(Entry::dynamic_dir(name, 
Some(parent_entry))),
-                _phantom: PhantomData,
-            }
-        }
-        #[cfg(not(CONFIG_DEBUG_FS))]
-        ScopedDir::empty()
-    }
-
     /// Creates a new scope, which is a directory associated with some data 
`T`.
     ///
     /// The created directory will be a subdirectory of `self`. The `init` 
closure is called to
@@ -427,7 +406,7 @@ fn scoped_dir<'data>(&self, name: &CStr) -> 
ScopedDir<'data, 'static> {
     /// The entire directory tree created within the scope will be removed 
when the returned
     /// `Scope` handle is dropped.
     pub fn scope<'a, T: 'a, E: 'a, F>(
-        &'a self,
+        &self,
         data: impl PinInit<T, E> + 'a,
         name: &'a CStr,
         init: F,
@@ -435,8 +414,22 @@ pub fn scope<'a, T: 'a, E: 'a, F>(
     where
         F: for<'data, 'dir> FnOnce(&'data T, &'dir ScopedDir<'data, 'dir>) + 
'a,
     {
-        Scope::new(data, |data| {
-            let scoped = self.scoped_dir(name);
+        // Clone the parent entry so the closure doesn't need to borrow `self`.
+        #[cfg(CONFIG_DEBUG_FS)]
+        let parent_entry = self.0.clone();
+
+        Scope::new(data, move |data| {
+            #[cfg(CONFIG_DEBUG_FS)]
+            let scoped = match parent_entry {
+                None => ScopedDir::empty(),
+                Some(entry) => ScopedDir {
+                    entry: ManuallyDrop::new(Entry::dynamic_dir(name, 
Some(entry))),
+                    _phantom: PhantomData,
+                },
+            };
+            #[cfg(not(CONFIG_DEBUG_FS))]
+            let scoped = ScopedDir::empty();
+
             init(data, &scoped);
             scoped.into_entry()
         })
-- 
2.52.0

Reply via email to