Merge tag 'idmapped-mounts-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git...
[platform/kernel/linux-rpi.git] / fs / overlayfs / super.c
index b702c57..fdd72f1 100644 (file)
@@ -264,11 +264,20 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
        struct super_block *upper_sb;
        int ret;
 
-       if (!ovl_upper_mnt(ofs))
-               return 0;
+       ret = ovl_sync_status(ofs);
+       /*
+        * We have to always set the err, because the return value isn't
+        * checked in syncfs, and instead indirectly return an error via
+        * the sb's writeback errseq, which VFS inspects after this call.
+        */
+       if (ret < 0) {
+               errseq_set(&sb->s_wb_err, -EIO);
+               return -EIO;
+       }
+
+       if (!ret)
+               return ret;
 
-       if (!ovl_should_sync(ofs))
-               return 0;
        /*
         * Not called for sync(2) call or an emergency sync (SB_I_SKIP_SYNC).
         * All the super blocks will be iterated, including upper_sb.
@@ -1932,6 +1941,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        unsigned int numlower;
        int err;
 
+       err = -EIO;
+       if (WARN_ON(sb->s_user_ns != current_user_ns()))
+               goto out;
+
        sb->s_d_op = &ovl_dentry_operations;
 
        err = -ENOMEM;
@@ -1998,6 +2011,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &ovl_super_operations;
 
        if (ofs->config.upperdir) {
+               struct super_block *upper_sb;
+
                if (!ofs->config.workdir) {
                        pr_err("missing 'workdir'\n");
                        goto out_err;
@@ -2007,6 +2022,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto out_err;
 
+               upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
+               if (!ovl_should_sync(ofs)) {
+                       ofs->errseq = errseq_sample(&upper_sb->s_wb_err);
+                       if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) {
+                               err = -EIO;
+                               pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n");
+                               goto out_err;
+                       }
+               }
+
                err = ovl_get_workdir(sb, ofs, &upperpath);
                if (err)
                        goto out_err;
@@ -2014,9 +2039,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (!ofs->workdir)
                        sb->s_flags |= SB_RDONLY;
 
-               sb->s_stack_depth = ovl_upper_mnt(ofs)->mnt_sb->s_stack_depth;
-               sb->s_time_gran = ovl_upper_mnt(ofs)->mnt_sb->s_time_gran;
-
+               sb->s_stack_depth = upper_sb->s_stack_depth;
+               sb->s_time_gran = upper_sb->s_time_gran;
        }
        oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs, layers);
        err = PTR_ERR(oe);