Re: [PATCH] ovl: factor out some common helpers for backing files io

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[forgot to CC overlayfs list]

On Tue, Sep 12, 2023 at 9:54 PM Amir Goldstein <amir73il@xxxxxxxxx> wrote:
>
> Overlayfs stores its files data in backing files on other filesystems.
>
> Factor out some common helpers to perform io to backing files, that will
> later be reused by fuse passthrough code.
>
> Suggested-by: Miklos Szeredi <miklos@xxxxxxxxxx>
> Link: https://lore.kernel.org/r/CAJfpeguhmZbjP3JLqtUy0AdWaHOkAPWeP827BBWwRFEAUgnUcQ@xxxxxxxxxxxxxx
> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> ---
>
> Miklos,
>
> This is the re-factoring that you suggested in the FUSE passthrough
> patches discussion linked above.
>
> This patch is based on the overlayfs prep patch set I just posted [1].
>
> Although overlayfs currently is the only user of these backing file
> helpers, I am sending this patch to a wider audience in case other
> filesystem developers want to comment on the abstraction.
>
> We could perhaps later considering moving backing_file_open() helper
> and related code to backing_file.c.
>
> In any case, if there are no objections, I plan to queue this work
> for 6.7 via the overlayfs tree.
>
> Thanks,
> Amir.
>
> [1] https://lore.kernel.org/linux-unionfs/20230912173653.3317828-1-amir73il@xxxxxxxxx/
>
>
>  MAINTAINERS                  |   2 +
>  fs/Kconfig                   |   4 +
>  fs/Makefile                  |   1 +
>  fs/backing_file.c            | 160 +++++++++++++++++++++++++++++++++++
>  fs/overlayfs/Kconfig         |   1 +
>  fs/overlayfs/file.c          | 137 ++----------------------------
>  fs/overlayfs/overlayfs.h     |   2 -
>  fs/overlayfs/super.c         |  11 +--
>  include/linux/backing_file.h |  22 +++++
>  9 files changed, 199 insertions(+), 141 deletions(-)
>  create mode 100644 fs/backing_file.c
>  create mode 100644 include/linux/backing_file.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 90f13281d297..4e1d21773e0e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16092,7 +16092,9 @@ L:      linux-unionfs@xxxxxxxxxxxxxxx
>  S:     Supported
>  T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
>  F:     Documentation/filesystems/overlayfs.rst
> +F:     fs/backing_file.c
>  F:     fs/overlayfs/
> +F:     include/linux/backing_file.h
>
>  P54 WIRELESS DRIVER
>  M:     Christian Lamparter <chunkeey@xxxxxxxxxxxxxx>
> diff --git a/fs/Kconfig b/fs/Kconfig
> index aa7e03cc1941..9027a88ffa47 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -26,6 +26,10 @@ config LEGACY_DIRECT_IO
>         depends on BUFFER_HEAD
>         bool
>
> +# Common backing file helpers
> +config FS_BACKING_FILE
> +       bool
> +
>  if BLOCK
>
>  source "fs/ext2/Kconfig"
> diff --git a/fs/Makefile b/fs/Makefile
> index f9541f40be4e..95ef06cff388 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -39,6 +39,7 @@ obj-$(CONFIG_COMPAT_BINFMT_ELF)       += compat_binfmt_elf.o
>  obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o
>  obj-$(CONFIG_BINFMT_FLAT)      += binfmt_flat.o
>
> +obj-$(CONFIG_FS_BACKING_FILE)  += backing_file.o
>  obj-$(CONFIG_FS_MBCACHE)       += mbcache.o
>  obj-$(CONFIG_FS_POSIX_ACL)     += posix_acl.o
>  obj-$(CONFIG_NFS_COMMON)       += nfs_common/
> diff --git a/fs/backing_file.c b/fs/backing_file.c
> new file mode 100644
> index 000000000000..ea895ca1639d
> --- /dev/null
> +++ b/fs/backing_file.c
> @@ -0,0 +1,160 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Common helpers for backing file io.
> + * Forked from fs/overlayfs/file.c.
> + *
> + * Copyright (C) 2017 Red Hat, Inc.
> + * Copyright (C) 2023 CTERA Networks.
> + */
> +
> +#include <linux/backing_file.h>
> +
> +struct backing_aio_req {
> +       struct kiocb iocb;
> +       refcount_t ref;
> +       struct kiocb *orig_iocb;
> +       void (*cleanup)(struct kiocb *, long);
> +};
> +
> +static struct kmem_cache *backing_aio_req_cachep;
> +
> +#define BACKING_IOCB_MASK \
> +       (IOCB_NOWAIT | IOCB_HIPRI | IOCB_DSYNC | IOCB_SYNC | IOCB_APPEND)
> +
> +static rwf_t iocb_to_rw_flags(int flags)
> +{
> +       return (__force rwf_t)(flags & BACKING_IOCB_MASK);
> +}
> +
> +static void backing_aio_put(struct backing_aio_req *aio_req)
> +{
> +       if (refcount_dec_and_test(&aio_req->ref)) {
> +               fput(aio_req->iocb.ki_filp);
> +               kmem_cache_free(backing_aio_req_cachep, aio_req);
> +       }
> +}
> +
> +/* Completion for submitted/failed async rw io */
> +static void backing_aio_cleanup(struct backing_aio_req *aio_req, long res)
> +{
> +       struct kiocb *iocb = &aio_req->iocb;
> +       struct kiocb *orig_iocb = aio_req->orig_iocb;
> +
> +       if (iocb->ki_flags & IOCB_WRITE)
> +               kiocb_end_write(iocb);
> +
> +       orig_iocb->ki_pos = iocb->ki_pos;
> +       if (aio_req->cleanup)
> +               aio_req->cleanup(orig_iocb, res);
> +
> +       backing_aio_put(aio_req);
> +}
> +
> +/* Completion for submitted async rw io */
> +static void backing_aio_rw_complete(struct kiocb *iocb, long res)
> +{
> +       struct backing_aio_req *aio_req = container_of(iocb,
> +                                              struct backing_aio_req, iocb);
> +       struct kiocb *orig_iocb = aio_req->orig_iocb;
> +
> +       backing_aio_cleanup(aio_req, res);
> +       orig_iocb->ki_complete(orig_iocb, res);
> +}
> +
> +
> +ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter,
> +                              struct kiocb *iocb, int flags,
> +                              void (*cleanup)(struct kiocb *, long))
> +{
> +       struct backing_aio_req *aio_req = NULL;
> +       ssize_t ret;
> +
> +       if (!iov_iter_count(iter))
> +               return 0;
> +
> +       if (iocb->ki_flags & IOCB_DIRECT &&
> +           !(file->f_mode & FMODE_CAN_ODIRECT))
> +               return -EINVAL;
> +
> +       if (is_sync_kiocb(iocb)) {
> +               rwf_t rwf = iocb_to_rw_flags(flags);
> +
> +               ret = vfs_iter_read(file, iter, &iocb->ki_pos, rwf);
> +               if (cleanup)
> +                       cleanup(iocb, ret);
> +       } else {
> +               aio_req = kmem_cache_zalloc(backing_aio_req_cachep, GFP_KERNEL);
> +               if (!aio_req)
> +                       return -ENOMEM;
> +
> +               aio_req->orig_iocb = iocb;
> +               aio_req->cleanup = cleanup;
> +               kiocb_clone(&aio_req->iocb, iocb, get_file(file));
> +               aio_req->iocb.ki_complete = backing_aio_rw_complete;
> +               refcount_set(&aio_req->ref, 2);
> +               ret = vfs_iocb_iter_read(file, &aio_req->iocb, iter);
> +               backing_aio_put(aio_req);
> +               if (ret != -EIOCBQUEUED)
> +                       backing_aio_cleanup(aio_req, ret);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(backing_file_read_iter);
> +
> +ssize_t backing_file_write_iter(struct file *file, struct iov_iter *iter,
> +                               struct kiocb *iocb, int flags,
> +                               void (*cleanup)(struct kiocb *, long))
> +{
> +       ssize_t ret;
> +
> +       if (!iov_iter_count(iter))
> +               return 0;
> +
> +       if (iocb->ki_flags & IOCB_DIRECT &&
> +           !(file->f_mode & FMODE_CAN_ODIRECT))
> +               return -EINVAL;
> +
> +       if (is_sync_kiocb(iocb)) {
> +               rwf_t rwf = iocb_to_rw_flags(flags);
> +
> +               file_start_write(file);
> +               ret = vfs_iter_write(file, iter, &iocb->ki_pos, rwf);
> +               file_end_write(file);
> +               if (cleanup)
> +                       cleanup(iocb, ret);
> +       } else {
> +               struct backing_aio_req *aio_req;
> +
> +               aio_req = kmem_cache_zalloc(backing_aio_req_cachep, GFP_KERNEL);
> +               if (!aio_req)
> +                       return -ENOMEM;
> +
> +               aio_req->orig_iocb = iocb;
> +               aio_req->cleanup = cleanup;
> +               kiocb_clone(&aio_req->iocb, iocb, get_file(file));
> +               aio_req->iocb.ki_flags = flags;
> +               aio_req->iocb.ki_complete = backing_aio_rw_complete;
> +               refcount_set(&aio_req->ref, 2);
> +               kiocb_start_write(&aio_req->iocb);
> +               ret = vfs_iocb_iter_write(file, &aio_req->iocb, iter);
> +               backing_aio_put(aio_req);
> +               if (ret != -EIOCBQUEUED)
> +                       backing_aio_cleanup(aio_req, ret);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(backing_file_write_iter);
> +
> +static int __init backing_aio_init(void)
> +{
> +       backing_aio_req_cachep = kmem_cache_create("backing_aio_req",
> +                                          sizeof(struct backing_aio_req),
> +                                          0, SLAB_HWCACHE_ALIGN, NULL);
> +       if (!backing_aio_req_cachep)
> +               return -ENOMEM;
> +
> +       return 0;
> +}
> +fs_initcall(backing_aio_init);
> diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig
> index fec5020c3495..7f52d9031cff 100644
> --- a/fs/overlayfs/Kconfig
> +++ b/fs/overlayfs/Kconfig
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  config OVERLAY_FS
>         tristate "Overlay filesystem support"
> +       select FS_BACKING_FILE
>         select EXPORTFS
>         help
>           An overlay filesystem combines two filesystems - an 'upper' filesystem
> diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
> index 05ec614f7054..81fe6a85cad9 100644
> --- a/fs/overlayfs/file.c
> +++ b/fs/overlayfs/file.c
> @@ -13,16 +13,9 @@
>  #include <linux/security.h>
>  #include <linux/mm.h>
>  #include <linux/fs.h>
> +#include <linux/backing_file.h>
>  #include "overlayfs.h"
>
> -struct ovl_aio_req {
> -       struct kiocb iocb;
> -       refcount_t ref;
> -       struct kiocb *orig_iocb;
> -};
> -
> -static struct kmem_cache *ovl_aio_request_cachep;
> -
>  static char ovl_whatisit(struct inode *inode, struct inode *realinode)
>  {
>         if (realinode != ovl_inode_upper(inode))
> @@ -262,24 +255,8 @@ static void ovl_file_accessed(struct file *file)
>         touch_atime(&file->f_path);
>  }
>
> -#define OVL_IOCB_MASK \
> -       (IOCB_NOWAIT | IOCB_HIPRI | IOCB_DSYNC | IOCB_SYNC | IOCB_APPEND)
> -
> -static rwf_t iocb_to_rw_flags(int flags)
> -{
> -       return (__force rwf_t)(flags & OVL_IOCB_MASK);
> -}
> -
> -static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
> -{
> -       if (refcount_dec_and_test(&aio_req->ref)) {
> -               fput(aio_req->iocb.ki_filp);
> -               kmem_cache_free(ovl_aio_request_cachep, aio_req);
> -       }
> -}
> -
>  /* Completion for submitted/failed sync/async rw io */
> -static void ovl_rw_complete(struct kiocb *orig_iocb)
> +static void ovl_rw_complete(struct kiocb *orig_iocb, long res)
>  {
>         struct file *file = orig_iocb->ki_filp;
>
> @@ -292,32 +269,6 @@ static void ovl_rw_complete(struct kiocb *orig_iocb)
>         }
>  }
>
> -/* Completion for submitted/failed async rw io */
> -static void ovl_aio_cleanup(struct ovl_aio_req *aio_req)
> -{
> -       struct kiocb *iocb = &aio_req->iocb;
> -       struct kiocb *orig_iocb = aio_req->orig_iocb;
> -
> -       if (iocb->ki_flags & IOCB_WRITE)
> -               kiocb_end_write(iocb);
> -
> -       orig_iocb->ki_pos = iocb->ki_pos;
> -       ovl_rw_complete(orig_iocb);
> -
> -       ovl_aio_put(aio_req);
> -}
> -
> -/* Completion for submitted async rw io */
> -static void ovl_aio_rw_complete(struct kiocb *iocb, long res)
> -{
> -       struct ovl_aio_req *aio_req = container_of(iocb,
> -                                                  struct ovl_aio_req, iocb);
> -       struct kiocb *orig_iocb = aio_req->orig_iocb;
> -
> -       ovl_aio_cleanup(aio_req);
> -       orig_iocb->ki_complete(orig_iocb, res);
> -}
> -
>  static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
>  {
>         struct file *file = iocb->ki_filp;
> @@ -332,38 +283,10 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
>         if (ret)
>                 return ret;
>
> -       ret = -EINVAL;
> -       if (iocb->ki_flags & IOCB_DIRECT &&
> -           !(real.file->f_mode & FMODE_CAN_ODIRECT))
> -               goto out_fdput;
> -
>         old_cred = ovl_override_creds(file_inode(file)->i_sb);
> -       if (is_sync_kiocb(iocb)) {
> -               rwf_t rwf = iocb_to_rw_flags(iocb->ki_flags);
> -
> -               ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, rwf);
> -               ovl_rw_complete(iocb);
> -       } else {
> -               struct ovl_aio_req *aio_req;
> -
> -               ret = -ENOMEM;
> -               aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL);
> -               if (!aio_req)
> -                       goto out;
> -
> -               real.flags = 0;
> -               aio_req->orig_iocb = iocb;
> -               kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
> -               aio_req->iocb.ki_complete = ovl_aio_rw_complete;
> -               refcount_set(&aio_req->ref, 2);
> -               ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
> -               ovl_aio_put(aio_req);
> -               if (ret != -EIOCBQUEUED)
> -                       ovl_aio_cleanup(aio_req);
> -       }
> -out:
> +       ret = backing_file_read_iter(real.file, iter, iocb, iocb->ki_flags,
> +                                    ovl_rw_complete);
>         revert_creds(old_cred);
> -out_fdput:
>         fdput(real);
>
>         return ret;
> @@ -392,45 +315,13 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
>         if (ret)
>                 goto out_unlock;
>
> -       ret = -EINVAL;
> -       if (iocb->ki_flags & IOCB_DIRECT &&
> -           !(real.file->f_mode & FMODE_CAN_ODIRECT))
> -               goto out_fdput;
> -
>         if (!ovl_should_sync(OVL_FS(inode->i_sb)))
>                 flags &= ~(IOCB_DSYNC | IOCB_SYNC);
>
>         old_cred = ovl_override_creds(inode->i_sb);
> -       if (is_sync_kiocb(iocb)) {
> -               rwf_t rwf = iocb_to_rw_flags(flags);
> -
> -               file_start_write(real.file);
> -               ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, rwf);
> -               file_end_write(real.file);
> -               ovl_rw_complete(iocb);
> -       } else {
> -               struct ovl_aio_req *aio_req;
> -
> -               ret = -ENOMEM;
> -               aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL);
> -               if (!aio_req)
> -                       goto out;
> -
> -               real.flags = 0;
> -               aio_req->orig_iocb = iocb;
> -               kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
> -               aio_req->iocb.ki_flags = flags;
> -               aio_req->iocb.ki_complete = ovl_aio_rw_complete;
> -               refcount_set(&aio_req->ref, 2);
> -               kiocb_start_write(&aio_req->iocb);
> -               ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
> -               ovl_aio_put(aio_req);
> -               if (ret != -EIOCBQUEUED)
> -                       ovl_aio_cleanup(aio_req);
> -       }
> -out:
> +       ret = backing_file_write_iter(real.file, iter, iocb, flags,
> +                                     ovl_rw_complete);
>         revert_creds(old_cred);
> -out_fdput:
>         fdput(real);
>
>  out_unlock:
> @@ -742,19 +633,3 @@ const struct file_operations ovl_file_operations = {
>         .copy_file_range        = ovl_copy_file_range,
>         .remap_file_range       = ovl_remap_file_range,
>  };
> -
> -int __init ovl_aio_request_cache_init(void)
> -{
> -       ovl_aio_request_cachep = kmem_cache_create("ovl_aio_req",
> -                                                  sizeof(struct ovl_aio_req),
> -                                                  0, SLAB_HWCACHE_ALIGN, NULL);
> -       if (!ovl_aio_request_cachep)
> -               return -ENOMEM;
> -
> -       return 0;
> -}
> -
> -void ovl_aio_request_cache_destroy(void)
> -{
> -       kmem_cache_destroy(ovl_aio_request_cachep);
> -}
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index 9817b2dcb132..64b98e67e826 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -799,8 +799,6 @@ struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
>
>  /* file.c */
>  extern const struct file_operations ovl_file_operations;
> -int __init ovl_aio_request_cache_init(void);
> -void ovl_aio_request_cache_destroy(void);
>  int ovl_real_fileattr_get(const struct path *realpath, struct fileattr *fa);
>  int ovl_real_fileattr_set(const struct path *realpath, struct fileattr *fa);
>  int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa);
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index def266b5e2a3..8c132467fca1 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -1530,14 +1530,10 @@ static int __init ovl_init(void)
>         if (ovl_inode_cachep == NULL)
>                 return -ENOMEM;
>
> -       err = ovl_aio_request_cache_init();
> -       if (!err) {
> -               err = register_filesystem(&ovl_fs_type);
> -               if (!err)
> -                       return 0;
> +       err = register_filesystem(&ovl_fs_type);
> +       if (!err)
> +               return 0;
>
> -               ovl_aio_request_cache_destroy();
> -       }
>         kmem_cache_destroy(ovl_inode_cachep);
>
>         return err;
> @@ -1553,7 +1549,6 @@ static void __exit ovl_exit(void)
>          */
>         rcu_barrier();
>         kmem_cache_destroy(ovl_inode_cachep);
> -       ovl_aio_request_cache_destroy();
>  }
>
>  module_init(ovl_init);
> diff --git a/include/linux/backing_file.h b/include/linux/backing_file.h
> new file mode 100644
> index 000000000000..1428fe7b26bb
> --- /dev/null
> +++ b/include/linux/backing_file.h
> @@ -0,0 +1,22 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Common helpers for backing file io.
> + *
> + * Copyright (C) 2023 CTERA Networks.
> + */
> +
> +#ifndef _LINUX_BACKING_FILE_H
> +#define _LINUX_BACKING_FILE_H
> +
> +#include <linux/file.h>
> +#include <linux/uio.h>
> +#include <linux/fs.h>
> +
> +ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter,
> +                              struct kiocb *iocb, int flags,
> +                              void (*cleanup)(struct kiocb *, long));
> +ssize_t backing_file_write_iter(struct file *file, struct iov_iter *iter,
> +                               struct kiocb *iocb, int flags,
> +                               void (*cleanup)(struct kiocb *, long));
> +
> +#endif /* _LINUX_BACKING_FILE_H */
> --
> 2.34.1
>




[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux