Control: found 4.1.3-1

On 2015-05-26, Vagrant Cascadian wrote:
> LTSP has been using aufs to provide a writeable tmpfs layer on top of
> NFS since wheezy.
>
> With the switch to the overlay filesystem (after adjusting LTSP's
> initramfs-tools hooks to support overlay), it appears to fail due to an
> incompatibility with NFS. 

I haven't confirmed, but this may be fixed in mainline, not sure how
difficult it would be to backport to 4.1.x:

commit 7c03b5d45b8eebf0111125053d8fe887cc262ba6
Author: Miklos Szeredi <mszer...@suse.cz>
Date:   Mon Jun 22 13:53:48 2015 +0200

    ovl: allow distributed fs as lower layer
    
    Allow filesystems with .d_revalidate as lower layer(s), but not as upper
    layer.
    
    For local filesystems the rule was that modifications on the layers
    directly while being part of the overlay results in undefined behavior.
    
    This can easily be extended to distributed filesystems: we assume the tree
    used as lower layer is static, which means ->d_revalidate() should always
    return "1".  If that is not the case, return -ESTALE, don't try to work
    around the modification.
    
    Signed-off-by: Miklos Szeredi <mszer...@suse.cz>

diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index de9d2ee..8a08c58 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -273,10 +273,57 @@ static void ovl_dentry_release(struct dentry *dentry)
        }
 }
 
+static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       struct ovl_entry *oe = dentry->d_fsdata;
+       unsigned int i;
+       int ret = 1;
+
+       for (i = 0; i < oe->numlower; i++) {
+               struct dentry *d = oe->lowerstack[i].dentry;
+
+               if (d->d_flags & DCACHE_OP_REVALIDATE) {
+                       ret = d->d_op->d_revalidate(d, flags);
+                       if (ret < 0)
+                               return ret;
+                       if (!ret) {
+                               if (!(flags & LOOKUP_RCU))
+                                       d_invalidate(d);
+                               return -ESTALE;
+                       }
+               }
+       }
+       return 1;
+}
+
+static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int 
flags)
+{
+       struct ovl_entry *oe = dentry->d_fsdata;
+       unsigned int i;
+       int ret = 1;
+
+       for (i = 0; i < oe->numlower; i++) {
+               struct dentry *d = oe->lowerstack[i].dentry;
+
+               if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE) {
+                       ret = d->d_op->d_weak_revalidate(d, flags);
+                       if (ret <= 0)
+                               break;
+               }
+       }
+       return ret;
+}
+
 static const struct dentry_operations ovl_dentry_operations = {
        .d_release = ovl_dentry_release,
 };
 
+static const struct dentry_operations ovl_reval_dentry_operations = {
+       .d_release = ovl_dentry_release,
+       .d_revalidate = ovl_dentry_revalidate,
+       .d_weak_revalidate = ovl_dentry_weak_revalidate,
+};
+
 static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 {
        size_t size = offsetof(struct ovl_entry, lowerstack[numlower]);
@@ -288,6 +335,20 @@ static struct ovl_entry *ovl_alloc_entry(unsigned int 
numlower)
        return oe;
 }
 
+static bool ovl_dentry_remote(struct dentry *dentry)
+{
+       return dentry->d_flags &
+               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+}
+
+static bool ovl_dentry_weird(struct dentry *dentry)
+{
+       return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
+                                 DCACHE_MANAGE_TRANSIT |
+                                 DCACHE_OP_HASH |
+                                 DCACHE_OP_COMPARE);
+}
+
 static inline struct dentry *ovl_lookup_real(struct dentry *dir,
                                             struct qstr *name)
 {
@@ -303,9 +364,9 @@ static inline struct dentry *ovl_lookup_real(struct dentry 
*dir,
        } else if (!dentry->d_inode) {
                dput(dentry);
                dentry = NULL;
-       } else if (dentry->d_flags & DCACHE_MANAGED_DENTRY) {
+       } else if (ovl_dentry_weird(dentry)) {
                dput(dentry);
-               /* Don't support traversing automounts */
+               /* Don't support traversing automounts and other weirdness */
                dentry = ERR_PTR(-EREMOTE);
        }
        return dentry;
@@ -354,6 +415,11 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry 
*dentry,
                        goto out;
 
                if (this) {
+                       if (unlikely(ovl_dentry_remote(this))) {
+                               dput(this);
+                               err = -EREMOTE;
+                               goto out;
+                       }
                        if (ovl_is_whiteout(this)) {
                                dput(this);
                                this = NULL;
@@ -698,25 +764,6 @@ static void ovl_unescape(char *s)
        }
 }
 
-static bool ovl_is_allowed_fs_type(struct dentry *root)
-{
-       const struct dentry_operations *dop = root->d_op;
-
-       /*
-        * We don't support:
-        *  - autofs
-        *  - filesystems with revalidate (FIXME for lower layer)
-        *  - filesystems with case insensitive names
-        */
-       if (dop &&
-           (dop->d_manage ||
-            dop->d_revalidate || dop->d_weak_revalidate ||
-            dop->d_compare || dop->d_hash)) {
-               return false;
-       }
-       return true;
-}
-
 static int ovl_mount_dir_noesc(const char *name, struct path *path)
 {
        int err = -EINVAL;
@@ -731,7 +778,7 @@ static int ovl_mount_dir_noesc(const char *name, struct 
path *path)
                goto out;
        }
        err = -EINVAL;
-       if (!ovl_is_allowed_fs_type(path->dentry)) {
+       if (ovl_dentry_weird(path->dentry)) {
                pr_err("overlayfs: filesystem on '%s' not supported\n", name);
                goto out_put;
        }
@@ -755,13 +802,21 @@ static int ovl_mount_dir(const char *name, struct path 
*path)
        if (tmp) {
                ovl_unescape(tmp);
                err = ovl_mount_dir_noesc(tmp, path);
+
+               if (!err)
+                       if (ovl_dentry_remote(path->dentry)) {
+                               pr_err("overlayfs: filesystem on '%s' not 
supported as upperdir\n",
+                                      tmp);
+                               path_put(path);
+                               err = -EINVAL;
+                       }
                kfree(tmp);
        }
        return err;
 }
 
 static int ovl_lower_dir(const char *name, struct path *path, long *namelen,
-                        int *stack_depth)
+                        int *stack_depth, bool *remote)
 {
        int err;
        struct kstatfs statfs;
@@ -778,6 +833,9 @@ static int ovl_lower_dir(const char *name, struct path 
*path, long *namelen,
        *namelen = max(*namelen, statfs.f_namelen);
        *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);
 
+       if (ovl_dentry_remote(path->dentry))
+               *remote = true;
+
        return 0;
 
 out_put:
@@ -831,6 +889,7 @@ static int ovl_fill_super(struct super_block *sb, void 
*data, int silent)
        unsigned int numlower;
        unsigned int stacklen = 0;
        unsigned int i;
+       bool remote = false;
        int err;
 
        err = -ENOMEM;
@@ -904,7 +963,8 @@ static int ovl_fill_super(struct super_block *sb, void 
*data, int silent)
        lower = lowertmp;
        for (numlower = 0; numlower < stacklen; numlower++) {
                err = ovl_lower_dir(lower, &stack[numlower],
-                                   &ufs->lower_namelen, &sb->s_stack_depth);
+                                   &ufs->lower_namelen, &sb->s_stack_depth,
+                                   &remote);
                if (err)
                        goto out_put_lowerpath;
 
@@ -962,7 +1022,10 @@ static int ovl_fill_super(struct super_block *sb, void 
*data, int silent)
        if (!ufs->upper_mnt)
                sb->s_flags |= MS_RDONLY;
 
-       sb->s_d_op = &ovl_dentry_operations;
+       if (remote)
+               sb->s_d_op = &ovl_reval_dentry_operations;
+       else
+               sb->s_d_op = &ovl_dentry_operations;
 
        err = -ENOMEM;
        oe = ovl_alloc_entry(numlower);


live well,
  vagrant

Attachment: signature.asc
Description: PGP signature

Reply via email to