diff mbox series

[RFC,2/3] libfs: add simple directory iteration function with callback

Message ID 20250318194111.19419-3-James.Bottomley@HansenPartnership.com (mailing list archive)
State New
Headers show
Series create simple libfs directory iterator and make efivarfs use it | expand

Commit Message

James Bottomley March 18, 2025, 7:41 p.m. UTC
The current iterate_dir() infrastructure is somewhat cumbersome to use
from within the kernel.  Introduce a lighter weight
simple_iterate_dir() function that directly iterates the directory and
executes a callback for each positive dentry.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 fs/libfs.c         | 33 +++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 35 insertions(+)

Comments

Ard Biesheuvel March 18, 2025, 9:33 p.m. UTC | #1
On Tue, 18 Mar 2025 at 20:45, James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
> The current iterate_dir() infrastructure is somewhat cumbersome to use
> from within the kernel.  Introduce a lighter weight
> simple_iterate_dir() function that directly iterates the directory and
> executes a callback for each positive dentry.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
>  fs/libfs.c         | 33 +++++++++++++++++++++++++++++++++
>  include/linux/fs.h |  2 ++
>  2 files changed, 35 insertions(+)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 816bfe6c0430..37da5fe25242 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -214,6 +214,39 @@ static void internal_readdir(struct dentry *dentry, struct dentry *cursor,
>         dput(next);
>  }
>
> +/**
> + * generic_iterate_call - iterate all entries executing @callback

This name doesn't match the name below.

> + *
> + * @dir: directory to iterate over
> + * @data: data passed to callback
> + * @callback: callback to call
> + *
> + * Iterates over all positive dentries that are direct children of
> + * @dir (so doesn't include . and ..) and executes the callback for
> + * each of them.  Note that because there's no struct *mnt, the caller
> + * is responsible for pinning the filesystem.
> + *
> + * If the @callback returns true, the iteration will continue and if
> + * it returns @false, it will stop (note that since the cursor is
> + * destroyed the next invocation will go back to the beginning again).
> + *
> + */
> +int simple_iterate_call(struct dentry *dir, void *data,
> +                       bool (*callback)(void *, struct dentry *))
> +{
> +       struct dentry *cursor = d_alloc_cursor(dir);
> +
> +       if (!cursor)
> +               return -ENOMEM;
> +
> +       internal_readdir(dir, cursor, data, true, callback);
> +
> +       dput(cursor);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(simple_iterate_call);
> +
>  static bool dcache_readdir_callback(void *data, struct dentry *entry)
>  {
>         struct dir_context *ctx = data;
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 2788df98080f..a84896f0b2d1 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -3531,6 +3531,8 @@ extern int simple_rename(struct mnt_idmap *, struct inode *,
>                          unsigned int);
>  extern void simple_recursive_removal(struct dentry *,
>                                void (*callback)(struct dentry *));
> +extern int simple_iterate_call(struct dentry *dir, void *data,
> +                              bool (*callback)(void *, struct dentry *));
>  extern int noop_fsync(struct file *, loff_t, loff_t, int);
>  extern ssize_t noop_direct_IO(struct kiocb *iocb, struct iov_iter *iter);
>  extern int simple_empty(struct dentry *);
> --
> 2.43.0
>
James Bottomley March 18, 2025, 9:50 p.m. UTC | #2
On Tue, 2025-03-18 at 22:33 +0100, Ard Biesheuvel wrote:
> On Tue, 18 Mar 2025 at 20:45, James Bottomley
> <James.Bottomley@hansenpartnership.com> wrote:
> > 
> > The current iterate_dir() infrastructure is somewhat cumbersome to
> > use from within the kernel.  Introduce a lighter weight
> > simple_iterate_dir() function that directly iterates the directory
> > and executes a callback for each positive dentry.
> > 
> > Signed-off-by: James Bottomley
> > <James.Bottomley@HansenPartnership.com>
> > ---
> >  fs/libfs.c         | 33 +++++++++++++++++++++++++++++++++
> >  include/linux/fs.h |  2 ++
> >  2 files changed, 35 insertions(+)
> > 
> > diff --git a/fs/libfs.c b/fs/libfs.c
> > index 816bfe6c0430..37da5fe25242 100644
> > --- a/fs/libfs.c
> > +++ b/fs/libfs.c
> > @@ -214,6 +214,39 @@ static void internal_readdir(struct dentry
> > *dentry, struct dentry *cursor,
> >         dput(next);
> >  }
> > 
> > +/**
> > + * generic_iterate_call - iterate all entries executing @callback
> 
> This name doesn't match the name below.

Right, I started out thinking the generic_ prefix was the preferred
one, but then simple_ looked better and I forgot to update the docbook.

Regards,

James
diff mbox series

Patch

diff --git a/fs/libfs.c b/fs/libfs.c
index 816bfe6c0430..37da5fe25242 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -214,6 +214,39 @@  static void internal_readdir(struct dentry *dentry, struct dentry *cursor,
 	dput(next);
 }
 
+/**
+ * generic_iterate_call - iterate all entries executing @callback
+ *
+ * @dir: directory to iterate over
+ * @data: data passed to callback
+ * @callback: callback to call
+ *
+ * Iterates over all positive dentries that are direct children of
+ * @dir (so doesn't include . and ..) and executes the callback for
+ * each of them.  Note that because there's no struct *mnt, the caller
+ * is responsible for pinning the filesystem.
+ *
+ * If the @callback returns true, the iteration will continue and if
+ * it returns @false, it will stop (note that since the cursor is
+ * destroyed the next invocation will go back to the beginning again).
+ *
+ */
+int simple_iterate_call(struct dentry *dir, void *data,
+			bool (*callback)(void *, struct dentry *))
+{
+	struct dentry *cursor = d_alloc_cursor(dir);
+
+	if (!cursor)
+		return -ENOMEM;
+
+	internal_readdir(dir, cursor, data, true, callback);
+
+	dput(cursor);
+
+	return 0;
+}
+EXPORT_SYMBOL(simple_iterate_call);
+
 static bool dcache_readdir_callback(void *data, struct dentry *entry)
 {
 	struct dir_context *ctx = data;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2788df98080f..a84896f0b2d1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3531,6 +3531,8 @@  extern int simple_rename(struct mnt_idmap *, struct inode *,
 			 unsigned int);
 extern void simple_recursive_removal(struct dentry *,
                               void (*callback)(struct dentry *));
+extern int simple_iterate_call(struct dentry *dir, void *data,
+			       bool (*callback)(void *, struct dentry *));
 extern int noop_fsync(struct file *, loff_t, loff_t, int);
 extern ssize_t noop_direct_IO(struct kiocb *iocb, struct iov_iter *iter);
 extern int simple_empty(struct dentry *);