summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/namei.c
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2023-04-27 13:39:09 +0300
committerAmir Goldstein <amir73il@gmail.com>2023-06-19 14:01:14 +0300
commit42dd69ae1af42cf72d167e63a039b8c63653eb7f (patch)
treeda3f8b549fc66bfbf52747724869f7d9a2da28bb /fs/overlayfs/namei.c
parent416656447864ef0fc2430525499f52a4a370a0ab (diff)
downloadlinux-42dd69ae1af42cf72d167e63a039b8c63653eb7f.tar.gz
linux-42dd69ae1af42cf72d167e63a039b8c63653eb7f.tar.bz2
linux-42dd69ae1af42cf72d167e63a039b8c63653eb7f.zip
ovl: implement lazy lookup of lowerdata in data-only layers
Defer lookup of lowerdata in the data-only layers to first data access or before copy up. We perform lowerdata lookup before copy up even if copy up is metadata only copy up. We can further optimize this lookup later if needed. We do best effort lazy lookup of lowerdata for d_real_inode(), because this interface does not expect errors. The only current in-tree caller of d_real_inode() is trace_uprobe and this caller is likely going to be followed reading from the file, before placing uprobes on offset within the file, so lowerdata should be available when setting the uprobe. Tested-by: kernel test robot <oliver.sang@intel.com> Reviewed-by: Alexander Larsson <alexl@redhat.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/namei.c')
-rw-r--r--fs/overlayfs/namei.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 605108f0dbe9..b3b40bc9a5ab 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -889,6 +889,52 @@ static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry,
return err;
}
+/* Lazy lookup of lowerdata */
+int ovl_maybe_lookup_lowerdata(struct dentry *dentry)
+{
+ struct inode *inode = d_inode(dentry);
+ const char *redirect = ovl_lowerdata_redirect(inode);
+ struct ovl_path datapath = {};
+ const struct cred *old_cred;
+ int err;
+
+ if (!redirect || ovl_dentry_lowerdata(dentry))
+ return 0;
+
+ if (redirect[0] != '/')
+ return -EIO;
+
+ err = ovl_inode_lock_interruptible(inode);
+ if (err)
+ return err;
+
+ err = 0;
+ /* Someone got here before us? */
+ if (ovl_dentry_lowerdata(dentry))
+ goto out;
+
+ old_cred = ovl_override_creds(dentry->d_sb);
+ err = ovl_lookup_data_layers(dentry, redirect, &datapath);
+ revert_creds(old_cred);
+ if (err)
+ goto out_err;
+
+ err = ovl_dentry_set_lowerdata(dentry, &datapath);
+ if (err)
+ goto out_err;
+
+out:
+ ovl_inode_unlock(inode);
+ dput(datapath.dentry);
+
+ return err;
+
+out_err:
+ pr_warn_ratelimited("lazy lowerdata lookup failed (%pd2, err=%i)\n",
+ dentry, err);
+ goto out;
+}
+
struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{
@@ -1072,14 +1118,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
}
}
- /* Lookup absolute redirect from lower metacopy in data-only layers */
+ /* Defer lookup of lowerdata in data-only layers to first access */
if (d.metacopy && ctr && ofs->numdatalayer && d.absolute_redirect) {
- err = ovl_lookup_data_layers(dentry, d.redirect,
- &stack[ctr]);
- if (!err) {
- d.metacopy = false;
- ctr++;
- }
+ d.metacopy = false;
+ ctr++;
}
/*