ovl: prepare for lazy lookup of lowerdata inode
authorAmir Goldstein <amir73il@gmail.com>
Sun, 2 Apr 2023 18:56:49 +0000 (21:56 +0300)
committerAmir Goldstein <amir73il@gmail.com>
Mon, 19 Jun 2023 11:01:14 +0000 (14:01 +0300)
Make the code handle the case of numlower > 1 and missing lowerdata
dentry gracefully.

Missing lowerdata dentry is an indication for lazy lookup of lowerdata
and in that case the lowerdata_redirect path is stored in ovl_inode.

Following commits will defer lookup and perform the lazy lookup on
access.

Reviewed-by: Alexander Larsson <alexl@redhat.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/file.c
fs/overlayfs/inode.c
fs/overlayfs/super.c
fs/overlayfs/util.c

index 7c04f03..951683a 100644 (file)
@@ -115,6 +115,9 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
                ovl_path_real(dentry, &realpath);
        else
                ovl_path_realdata(dentry, &realpath);
+       /* TODO: lazy lookup of lowerdata */
+       if (!realpath.dentry)
+               return -EIO;
 
        /* Has it been copied up since we'd opened it? */
        if (unlikely(file_inode(real->file) != d_inode(realpath.dentry))) {
@@ -158,6 +161,10 @@ static int ovl_open(struct inode *inode, struct file *file)
        file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
        ovl_path_realdata(dentry, &realpath);
+       /* TODO: lazy lookup of lowerdata */
+       if (!realpath.dentry)
+               return -EIO;
+
        realfile = ovl_open_realfile(file, &realpath);
        if (IS_ERR(realfile))
                return PTR_ERR(realfile);
index 552059e..bf47a0a 100644 (file)
@@ -240,15 +240,22 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
                        /*
                         * If lower is not same as lowerdata or if there was
                         * no origin on upper, we can end up here.
+                        * With lazy lowerdata lookup, guess lowerdata blocks
+                        * from size to avoid lowerdata lookup on stat(2).
                         */
                        struct kstat lowerdatastat;
                        u32 lowermask = STATX_BLOCKS;
 
                        ovl_path_lowerdata(dentry, &realpath);
-                       err = vfs_getattr(&realpath, &lowerdatastat,
-                                         lowermask, flags);
-                       if (err)
-                               goto out;
+                       if (realpath.dentry) {
+                               err = vfs_getattr(&realpath, &lowerdatastat,
+                                                 lowermask, flags);
+                               if (err)
+                                       goto out;
+                       } else {
+                               lowerdatastat.blocks =
+                                       round_up(stat->size, stat->blksize) >> 9;
+                       }
                        stat->blocks = lowerdatastat.blocks;
                }
        }
@@ -709,6 +716,9 @@ static int ovl_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        struct inode *realinode = ovl_inode_realdata(inode);
        const struct cred *old_cred;
 
+       if (!realinode)
+               return -EIO;
+
        if (!realinode->i_op->fiemap)
                return -EOPNOTSUPP;
 
index 9de02ca..f3e5b43 100644 (file)
@@ -81,6 +81,14 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
        if (real && !inode && ovl_has_upperdata(d_inode(dentry)))
                return real;
 
+       /*
+        * XXX: We may need lazy lookup of lowerdata for !inode case to return
+        * the real lowerdata dentry.  The only current caller of d_real() with
+        * NULL inode is d_real_inode() from 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.
+        */
        lower = ovl_dentry_lowerdata(dentry);
        if (!lower)
                goto bug;
@@ -103,6 +111,9 @@ static int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak)
 {
        int ret = 1;
 
+       if (!d)
+               return 1;
+
        if (weak) {
                if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE)
                        ret =  d->d_op->d_weak_revalidate(d, flags);
index 72f565f..23c0224 100644 (file)
@@ -159,7 +159,7 @@ void ovl_dentry_init_flags(struct dentry *dentry, struct dentry *upperdentry,
 
        if (upperdentry)
                flags |= upperdentry->d_flags;
-       for (i = 0; i < ovl_numlower(oe); i++)
+       for (i = 0; i < ovl_numlower(oe) && lowerstack[i].dentry; i++)
                flags |= lowerstack[i].dentry->d_flags;
 
        spin_lock(&dentry->d_lock);