[RFC][PATCH 4/5] ovl: add support for copy file range from another fs
Amir Goldstein <[email protected]> Thu, 23 Jul 2026 13:48:47 +0200
| Newsgroups | org.kernel.vger.linux-unionfs,org.kernel.vger.linux-fsdevel |
|---|---|
| Message-ID | <[email protected]> |
It is technically possible for overlayfs to copy_file_range() from the base fs of the real layer. Set the vfs flag FOP_CROSS_FS_COPY and implement copy from another fs. Implementation of copy to another fs is a bit more subtle and will be handled by a followup patch. Signed-off-by: Amir Goldstein <[email protected]> --- fs/overlayfs/file.c | 22 ++++++++++++++++++++++ fs/overlayfs/ovl_entry.h | 7 ++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index f3d97eb146e85..169a48de565e9 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -533,6 +533,13 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, struct file *realfile_in, *realfile_out; loff_t ret; + /* + * Overlayfs may be able to copy to a non overlayfs dst which is on the + * same sb or same fs type as real file_in fs, but not implemented yet. + */ + if (WARN_ON_ONCE(!is_ovl_fs(inode_out->i_sb))) + return -EXDEV; + inode_lock(inode_out); if (op != OVL_DEDUPE) { /* Update mode */ @@ -547,6 +554,19 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, if (IS_ERR(realfile_out)) goto out_unlock; + /* + * Overlayfs may be able to copy from a non overlayfs src which is on + * the same sb or same fs type as upper fs. + */ + if (unlikely(!is_ovl_fs(inode_in->i_sb))) { + if (WARN_ON_ONCE(op != OVL_COPY)) { + ret = -EXDEV; + goto out_unlock; + } + realfile_in = file_in; + goto do_copy; + } + realfile_in = ovl_real_file(file_in); ret = PTR_ERR(realfile_in); if (IS_ERR(realfile_in)) @@ -565,6 +585,7 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, } } +do_copy: with_ovl_creds(inode_out->i_sb) { switch (op) { case OVL_COPY: @@ -660,6 +681,7 @@ const struct file_operations ovl_file_operations = { .splice_read = ovl_splice_read, .splice_write = ovl_splice_write, + .fop_flags = FOP_CROSS_FS_COPY, .copy_file_range = ovl_copy_file_range, .remap_file_range = ovl_remap_file_range, .setlease = generic_setlease, diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 80cad4ea96a3e..8a1862cf87d78 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -112,10 +112,15 @@ static inline struct mnt_idmap *ovl_upper_mnt_idmap(struct ovl_fs *ofs) extern struct file_system_type ovl_fs_type; +static inline bool is_ovl_fs(const struct super_block *sb) +{ + return sb->s_type == &ovl_fs_type; +} + static inline struct ovl_fs *OVL_FS(struct super_block *sb) { if (IS_ENABLED(CONFIG_OVERLAY_FS_DEBUG)) - WARN_ON_ONCE(sb->s_type != &ovl_fs_type); + WARN_ON_ONCE(!is_ovl_fs(sb)); return (struct ovl_fs *)sb->s_fs_info; } -- 2.54.0