ovl: relax same fs constrain for ovl_check_origin()
authorAmir Goldstein <amir73il@gmail.com>
Wed, 21 Jun 2017 12:28:34 +0000 (15:28 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 4 Jul 2017 20:03:17 +0000 (22:03 +0200)
For the case of all layers not on the same fs, try to decode the copy up
origin file handle on any of the lower layers.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/namei.c

index 277a55c8299a2976d29c0c664b8f08371d36dc49..6485beddaa1fb99124d5ab12722ce7c8ecc5b746 100644 (file)
@@ -272,28 +272,24 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
 static int ovl_check_origin(struct dentry *dentry, struct dentry *upperdentry,
                            struct path **stackp, unsigned int *ctrp)
 {
-       struct super_block *same_sb = ovl_same_sb(dentry->d_sb);
        struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;
        struct vfsmount *mnt;
-       struct dentry *origin;
+       struct dentry *origin = NULL;
+       int i;
 
-       if (!same_sb || !roe->numlower)
-               return 0;
 
-       /*
-       * Since all layers are on the same fs, we use the first layer for
-       * decoding the file handle.  We may get a disconnected dentry,
-       * which is fine, because we only need to hold the origin inode in
-       * cache and use its inode number.  We may even get a connected dentry,
-       * that is not under the first layer's root.  That is also fine for
-       * using it's inode number - it's the same as if we held a reference
-       * to a dentry in first layer that was moved under us.
-       */
-       mnt = roe->lowerstack[0].mnt;
-
-       origin = ovl_get_origin(upperdentry, mnt);
-       if (IS_ERR_OR_NULL(origin))
-               return PTR_ERR(origin);
+       for (i = 0; i < roe->numlower; i++) {
+               mnt = roe->lowerstack[i].mnt;
+               origin = ovl_get_origin(upperdentry, mnt);
+               if (IS_ERR(origin))
+                       return PTR_ERR(origin);
+
+               if (origin)
+                       break;
+       }
+
+       if (!origin)
+               return 0;
 
        BUG_ON(*stackp || *ctrp);
        *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY);
@@ -371,6 +367,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                }
                if (upperdentry && !d.is_dir) {
                        BUG_ON(!d.stop || d.redirect);
+                       /*
+                        * Lookup copy up origin by decoding origin file handle.
+                        * We may get a disconnected dentry, which is fine,
+                        * because we only need to hold the origin inode in
+                        * cache and use its inode number.  We may even get a
+                        * connected dentry, that is not under any of the lower
+                        * layers root.  That is also fine for using it's inode
+                        * number - it's the same as if we held a reference
+                        * to a dentry in lower layer that was moved under us.
+                        */
                        err = ovl_check_origin(dentry, upperdentry,
                                               &stack, &ctr);
                        if (err)