These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / overlayfs / super.c
index 1559894..000b2ed 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/fs.h>
 #include <linux/namei.h>
+#include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/security.h>
 #include <linux/mount.h>
@@ -75,12 +76,14 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry)
        if (oe->__upperdentry) {
                type = __OVL_PATH_UPPER;
 
-               if (oe->numlower) {
-                       if (S_ISDIR(dentry->d_inode->i_mode))
-                               type |= __OVL_PATH_MERGE;
-               } else if (!oe->opaque) {
+               /*
+                * Non-dir dentry can hold lower dentry from previous
+                * location. Its purity depends only on opaque flag.
+                */
+               if (oe->numlower && S_ISDIR(dentry->d_inode->i_mode))
+                       type |= __OVL_PATH_MERGE;
+               else if (!oe->opaque)
                        type |= __OVL_PATH_PURE;
-               }
        } else {
                if (oe->numlower > 1)
                        type |= __OVL_PATH_MERGE;
@@ -273,8 +276,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,
+       .d_select_inode = ovl_d_select_inode,
+};
+
+static const struct dentry_operations ovl_reval_dentry_operations = {
+       .d_release = ovl_dentry_release,
+       .d_select_inode = ovl_d_select_inode,
+       .d_revalidate = ovl_dentry_revalidate,
+       .d_weak_revalidate = ovl_dentry_weak_revalidate,
 };
 
 static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
@@ -288,6 +340,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,6 +369,10 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir,
        } else if (!dentry->d_inode) {
                dput(dentry);
                dentry = NULL;
+       } else if (ovl_dentry_weird(dentry)) {
+               dput(dentry);
+               /* Don't support traversing automounts and other weirdness */
+               dentry = ERR_PTR(-EREMOTE);
        }
        return dentry;
 }
@@ -350,6 +420,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;
@@ -473,6 +548,7 @@ static void ovl_put_super(struct super_block *sb)
        mntput(ufs->upper_mnt);
        for (i = 0; i < ufs->numlower; i++)
                mntput(ufs->lower_mnt[i]);
+       kfree(ufs->lower_mnt);
 
        kfree(ufs->config.lowerdir);
        kfree(ufs->config.upperdir);
@@ -694,25 +770,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:
-        *  - automount filesystems
-        *  - filesystems with revalidate (FIXME for lower layer)
-        *  - filesystems with case insensitive names
-        */
-       if (dop &&
-           (dop->d_manage || dop->d_automount ||
-            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;
@@ -727,7 +784,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;
        }
@@ -751,13 +808,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;
@@ -774,6 +839,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:
@@ -827,6 +895,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;
@@ -845,6 +914,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        sb->s_stack_depth = 0;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
        if (ufs->config.upperdir) {
                if (!ufs->config.workdir) {
                        pr_err("overlayfs: missing 'workdir'\n");
@@ -900,7 +970,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;
 
@@ -958,7 +1029,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);
@@ -980,9 +1054,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                oe->lowerstack[i].dentry = stack[i].dentry;
                oe->lowerstack[i].mnt = ufs->lower_mnt[i];
        }
+       kfree(stack);
 
        root_dentry->d_fsdata = oe;
 
+       ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode,
+                    root_dentry->d_inode);
+
        sb->s_magic = OVERLAYFS_SUPER_MAGIC;
        sb->s_op = &ovl_super_operations;
        sb->s_root = root_dentry;