power: rk818 charger: fix otg supply on/off error
[firefly-linux-kernel-4.4.55.git] / fs / overlayfs / super.c
index e38ee0fed24a2f7a343f294a793b6abea93f6f97..a1acc6004a91ddf3a175bdc3d94e57f5c4384484 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,6 +276,37 @@ static void ovl_dentry_release(struct dentry *dentry)
        }
 }
 
+static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
+{
+       struct dentry *real;
+
+       if (d_is_dir(dentry)) {
+               if (!inode || inode == d_inode(dentry))
+                       return dentry;
+               goto bug;
+       }
+
+       real = ovl_dentry_upper(dentry);
+       if (real && (!inode || inode == d_inode(real)))
+               return real;
+
+       real = ovl_dentry_lower(dentry);
+       if (!real)
+               goto bug;
+
+       if (!inode || inode == d_inode(real))
+               return real;
+
+       /* Handle recursion */
+       if (real->d_flags & DCACHE_OP_REAL)
+               return real->d_op->d_real(real, inode);
+
+bug:
+       WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry,
+            inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
+       return dentry;
+}
+
 static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct ovl_entry *oe = dentry->d_fsdata;
@@ -317,10 +351,13 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
 static const struct dentry_operations ovl_dentry_operations = {
        .d_release = ovl_dentry_release,
        .d_select_inode = ovl_d_select_inode,
+       .d_real = ovl_d_real,
 };
 
 static const struct dentry_operations ovl_reval_dentry_operations = {
        .d_release = ovl_dentry_release,
+       .d_select_inode = ovl_d_select_inode,
+       .d_real = ovl_d_real,
        .d_revalidate = ovl_dentry_revalidate,
        .d_weak_revalidate = ovl_dentry_weak_revalidate,
 };
@@ -910,6 +947,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");
@@ -1053,6 +1091,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        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;