[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <aDCrufEjtJeGjO6z@google.com>
Date: Fri, 23 May 2025 17:09:13 +0000
From: Alice Ryhl <aliceryhl@...gle.com>
To: Danilo Krummrich <dakr@...nel.org>
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>, Benno Lossin <lossin@...nel.org>,
Matthew Maurer <mmaurer@...gle.com>, Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>, Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
"Björn Roy Baron" <bjorn3_gh@...tonmail.com>, Benno Lossin <benno.lossin@...ton.me>,
Andreas Hindborg <a.hindborg@...nel.org>, Trevor Gross <tmgross@...ch.edu>,
"Rafael J. Wysocki" <rafael@...nel.org>, Sami Tolvanen <samitolvanen@...gle.com>,
Timur Tabi <ttabi@...dia.com>, linux-kernel@...r.kernel.org,
rust-for-linux@...r.kernel.org
Subject: Re: [PATCH v5 4/4] rust: samples: Add debugfs sample
On Fri, May 23, 2025 at 11:42:23AM +0200, Danilo Krummrich wrote:
> On Fri, May 23, 2025 at 11:14:23AM +0200, Greg Kroah-Hartman wrote:
> > On Thu, May 22, 2025 at 07:53:49PM +0200, Danilo Krummrich wrote:
> > > On Thu, May 22, 2025 at 04:15:46PM +0200, Greg Kroah-Hartman wrote:
> > > > If you really want to delete a debugfs file that you have created in the
> > > > past, then look it up and delete it with the call that is present for
> > > > that.
> > >
> > > This is promoting a C pattern (which for C code obviously makes a lot of sense),
> > > i.e. we have a function that creates a thing and another function that removes
> > > the thing given a handle of the created thing. Whether the handle is valid is
> > > the responsibility of the caller.
> > >
> > > In this case the handle would be the filename. For instance:
> > >
> > > debugfs_create_file("foo", parent, ...);
> > > debugfs_remove(debugfs_lookup("foo", parent));
> > >
> > > This leaves room to the caller for making mistakes, e.g. if the caller makes a
> > > typo in the filename. In this case we wouldn't even recognize it from the return
> > > value, since there is none.
> > >
> > > In Rust, we do things differently, i.e. we wrap things into an object that
> > > cleans up itself, once it goes out of scope. For instance:
> > >
> > > let file = debugfs::File::new("foo", parent);
> > >
> > > Subsequently we store file in a structure that represents the time we want this
> > > file to exist. Once it goes out of scope, it's removed automatically.
> > >
> > > This is better, since we can't make any mistakes anymore, i.e. we can't mess up
> > > the filename or pass the wrong parent to clean things up.
> > >
> > > Depending on whether the above was a misunderstanding and depending on how you
> > > think about it with this rationale, I have quite some more reasons why we don't
> > > want to have files / directories around in the filesystem without a
> > > corresponding object representation in Rust.
> > >
> > > But before I write up a lot more text, I'd like to see if we're not already on
> > > the same page. :-)
> >
> > Ok, let's knock up the api here first before worrying about the
> > implementation, as we seem to all be a bit confused as to what we want
> > to do.
> >
> > Ideally, yes, I would like to NOT have any rust structure represent a
> > debugfs file, as that is the way the C api has been evolving. We are
> > one step away from debugfs_create_file() being a void function that
> > doesn't return anything, and I don't want to see us go "backwards" here.
> >
> > But the main reason I did that work was to keep people from trying to
> > determine if a file creation worked or not and to do different logic
> > based on that. I think the Rust api CAN do both here, as you and Alice
> > have explained, so we should be ok.
> >
> > So how about this for an example api, two structures, debugfs::Directory
> > and debugfs::File, which have only two types of operations that can be
> > done on them:
> >
> > To create a debugfs directory, we do:
> >
> > let my_dir = debugfs::Directory::new("foo_dir", parent);
> >
> > There is no other Directory method, other than "drop", when the object
> > goes out of scope, which will clean up the directory and ALL child
> > objects at the same time (implementation details to be figured out
> > later.)
> >
> > That will ALWAYS succeed no matter if the backend debugfs call failed or
> > not, and you have no way of knowing if it really did create something or
> > not. That directory you can then use to pass into debugfs file or
> > directory creation functions.
> >
> > Same for creating a debugfs file, you would do something like:
> >
> > let my_file = debugfs::File::new("foo_file", my_dir);
> >
> > depending on the "file type" you want to create, there will be different
> > new_* methods (new_u32, new_u64, etc.).
> >
> > which also ALWAYS succeeds. And again, as you want to keep objects
> > around, you have to have a reference on it at all times for it to exist
> > in the filesystem. If you drop it, then it too will be removed from
> > debugfs.
>
> Great! That's exactly what I think the API should look like as well. :-)
>
> > And again, that's the only operation you can do on this object, there
> > are no other methods for it other than "new" and "drop".
>
> We probably still want
>
> let foo_dir = my_dir.subdir("foo_dir")
> foo_dir.file("foo_file")
>
> for convinience, rather than having to call
>
> let bar_dir = Dir::new("foo_dir", my_dir)
> File::new("bar_file", bar_dir)
>
> all the time. But otherwise, sounds reasonable to me.
>
> > Now there are issues with implementation details here like:
> > - Do you want to keep the list of file and dir objects in the rust
> > structure to manually clean them up when we go to drop the
> > directory?
> > - Do we want to force all files to be dropped before the directory?
> > Or do we want to just let the C side clean it all up automagically
> > instead?
> > and other things like that, but we can argue about that once we settle
> > on the outward-facing api first.
>
> The only thing I don't want to is to allow to leak files or directories, i.e.
>
> File::new("bar_file", bar_dir).leak()
>
> which keeps the file in the filesystem, but takes away the handle from the Rust
> side, such that it won't be removed from the filesystem anymore when the handle
> goes out of scope, which can cause nasty bugs. But I think there isn't any
> benefit to allow this anyways and it isn't needed with reference counting.
Why not have leak() for files only? That way, the files still go away
when you drop the directory, and you don't have to keep around a bunch
of File objects in your Rust structs.
Alice
Powered by blists - more mailing lists