Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / super.c
index 628cfcdc082341b54ea220bfce7bedada72ba1d3..eb7aa3e4ef05caf136f24e0565a28e6d1e0a1539 100644 (file)
@@ -539,6 +539,7 @@ void __ext4_error(struct super_block *sb, const char *function,
        printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n",
               sb->s_id, function, line, current->comm, &vaf);
        va_end(args);
+       save_error_info(sb, function, line);
 
        ext4_handle_error(sb);
 }
@@ -1051,7 +1052,7 @@ static void destroy_inodecache(void)
 void ext4_clear_inode(struct inode *inode)
 {
        invalidate_inode_buffers(inode);
-       end_writeback(inode);
+       clear_inode(inode);
        dquot_drop(inode);
        ext4_discard_preallocations(inode);
        if (EXT4_I(inode)->jinode) {
@@ -1492,6 +1493,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        const struct mount_opts *m;
+       kuid_t uid;
+       kgid_t gid;
        int arg = 0;
 
 #ifdef CONFIG_QUOTA
@@ -1518,10 +1521,20 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                         "Ignoring removed %s option", opt);
                return 1;
        case Opt_resuid:
-               sbi->s_resuid = arg;
+               uid = make_kuid(current_user_ns(), arg);
+               if (!uid_valid(uid)) {
+                       ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+                       return -1;
+               }
+               sbi->s_resuid = uid;
                return 1;
        case Opt_resgid:
-               sbi->s_resgid = arg;
+               gid = make_kgid(current_user_ns(), arg);
+               if (!gid_valid(gid)) {
+                       ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+                       return -1;
+               }
+               sbi->s_resgid = gid;
                return 1;
        case Opt_abort:
                sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
@@ -1776,12 +1789,14 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
                SEQ_OPTS_PRINT("%s", token2str(m->token));
        }
 
-       if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
+       if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) ||
            le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
-               SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
-       if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
+               SEQ_OPTS_PRINT("resuid=%u",
+                               from_kuid_munged(&init_user_ns, sbi->s_resuid));
+       if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) ||
            le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
-               SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
+               SEQ_OPTS_PRINT("resgid=%u",
+                               from_kgid_munged(&init_user_ns, sbi->s_resgid));
        def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
        if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
                SEQ_OPTS_PUTS("errors=remount-ro");
@@ -2473,6 +2488,23 @@ static ssize_t sbi_ui_store(struct ext4_attr *a,
        return count;
 }
 
+static ssize_t trigger_test_error(struct ext4_attr *a,
+                                 struct ext4_sb_info *sbi,
+                                 const char *buf, size_t count)
+{
+       int len = count;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (len && buf[len-1] == '\n')
+               len--;
+
+       if (len)
+               ext4_error(sbi->s_sb, "%.*s", len, buf);
+       return count;
+}
+
 #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \
 static struct ext4_attr ext4_attr_##_name = {                  \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
@@ -2503,6 +2535,7 @@ EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
 EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
 EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
 EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump);
+EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error);
 
 static struct attribute *ext4_attrs[] = {
        ATTR_LIST(delayed_allocation_blocks),
@@ -2517,6 +2550,7 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(mb_stream_req),
        ATTR_LIST(mb_group_prealloc),
        ATTR_LIST(max_writeback_mb_bump),
+       ATTR_LIST(trigger_fs_error),
        NULL,
 };
 
@@ -3087,9 +3121,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto out_free_orig;
        }
        sb->s_fs_info = sbi;
+       sbi->s_sb = sb;
        sbi->s_mount_opt = 0;
-       sbi->s_resuid = EXT4_DEF_RESUID;
-       sbi->s_resgid = EXT4_DEF_RESGID;
+       sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID);
+       sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID);
        sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
        sbi->s_sb_block = sb_block;
        if (sb->s_bdev->bd_part)
@@ -3209,8 +3244,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (def_mount_opts & EXT4_DEFM_DISCARD)
                set_opt(sb, DISCARD);
 
-       sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
-       sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+       sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+       sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
        sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;
        sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
        sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
@@ -4359,8 +4394,8 @@ static int ext4_unfreeze(struct super_block *sb)
 struct ext4_mount_options {
        unsigned long s_mount_opt;
        unsigned long s_mount_opt2;
-       uid_t s_resuid;
-       gid_t s_resgid;
+       kuid_t s_resuid;
+       kgid_t s_resgid;
        unsigned long s_commit_interval;
        u32 s_min_batch_time, s_max_batch_time;
 #ifdef CONFIG_QUOTA
@@ -4890,7 +4925,6 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                return -EIO;
        }
 
-       mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
        bh = ext4_bread(handle, inode, blk, 1, &err);
        if (!bh)
                goto out;
@@ -4906,16 +4940,13 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
        err = ext4_handle_dirty_metadata(handle, NULL, bh);
        brelse(bh);
 out:
-       if (err) {
-               mutex_unlock(&inode->i_mutex);
+       if (err)
                return err;
-       }
        if (inode->i_size < off + len) {
                i_size_write(inode, off + len);
                EXT4_I(inode)->i_disksize = inode->i_size;
                ext4_mark_inode_dirty(handle, inode);
        }
-       mutex_unlock(&inode->i_mutex);
        return len;
 }