Merge tag 'v3.10.103' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / ext4 / super.c
index fcf2401d490ac2bc945db0c624492634f6f3769d..dffff7953d9d68028029c649aee1d83f93d6ee6a 100644 (file)
@@ -400,9 +400,13 @@ static void ext4_handle_error(struct super_block *sb)
                ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
                sb->s_flags |= MS_RDONLY;
        }
-       if (test_opt(sb, ERRORS_PANIC))
+       if (test_opt(sb, ERRORS_PANIC)) {
+               if (EXT4_SB(sb)->s_journal &&
+                 !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
+                       return;
                panic("EXT4-fs (device %s): panic forced after error\n",
                        sb->s_id);
+       }
 }
 
 void __ext4_error(struct super_block *sb, const char *function,
@@ -576,8 +580,12 @@ void __ext4_abort(struct super_block *sb, const char *function,
                        jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
                save_error_info(sb, function, line);
        }
-       if (test_opt(sb, ERRORS_PANIC))
+       if (test_opt(sb, ERRORS_PANIC)) {
+               if (EXT4_SB(sb)->s_journal &&
+                 !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
+                       return;
                panic("EXT4-fs panic from previous error\n");
+       }
 }
 
 void ext4_msg(struct super_block *sb, const char *prefix, const char *fmt, ...)
@@ -803,6 +811,7 @@ static void ext4_put_super(struct super_block *sb)
                dump_orphan_list(sb, sbi);
        J_ASSERT(list_empty(&sbi->s_orphan));
 
+       sync_blockdev(sb->s_bdev);
        invalidate_bdev(sb->s_bdev);
        if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
                /*
@@ -964,7 +973,7 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb,
         * Currently we don't know the generation for parent directory, so
         * a generation of 0 means "accept any"
         */
-       inode = ext4_iget(sb, ino);
+       inode = ext4_iget_normal(sb, ino);
        if (IS_ERR(inode))
                return ERR_CAST(inode);
        if (generation && inode->i_generation != generation) {
@@ -1632,13 +1641,6 @@ static int parse_options(char *options, struct super_block *sb,
                                        "not specified");
                        return 0;
                }
-       } else {
-               if (sbi->s_jquota_fmt) {
-                       ext4_msg(sb, KERN_ERR, "journaled quota format "
-                                       "specified with no journaling "
-                                       "enabled");
-                       return 0;
-               }
        }
 #endif
        if (test_opt(sb, DIOREAD_NOLOCK)) {
@@ -1957,6 +1959,10 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
        }
 
        /* old crc16 code */
+       if (!(sbi->s_es->s_feature_ro_compat &
+             cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
+               return 0;
+
        offset = offsetof(struct ext4_group_desc, bg_checksum);
 
        crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
@@ -2147,6 +2153,16 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        while (es->s_last_orphan) {
                struct inode *inode;
 
+               /*
+                * We may have encountered an error during cleanup; if
+                * so, skip the rest.
+                */
+               if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
+                       jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
+                       es->s_last_orphan = 0;
+                       break;
+               }
+
                inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
                if (IS_ERR(inode)) {
                        es->s_last_orphan = 0;
@@ -4979,6 +4995,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
                                        EXT4_SB(sb)->s_jquota_fmt, type);
 }
 
+static void lockdep_set_quota_inode(struct inode *inode, int subclass)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+
+       /* The first argument of lockdep_set_subclass has to be
+        * *exactly* the same as the argument to init_rwsem() --- in
+        * this case, in init_once() --- or lockdep gets unhappy
+        * because the name of the lock is set using the
+        * stringification of the argument to init_rwsem().
+        */
+       (void) ei;      /* shut up clang warning if !CONFIG_LOCKDEP */
+       lockdep_set_subclass(&ei->i_data_sem, subclass);
+}
+
 /*
  * Standard function to be called on quota_on
  */
@@ -5018,8 +5048,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                if (err)
                        return err;
        }
-
-       return dquot_quota_on(sb, type, format_id, path);
+       lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA);
+       err = dquot_quota_on(sb, type, format_id, path);
+       if (err)
+               lockdep_set_quota_inode(path->dentry->d_inode,
+                                            I_DATA_SEM_NORMAL);
+       return err;
 }
 
 static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
@@ -5045,8 +5079,11 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
 
        /* Don't account quota for quota files to avoid recursion */
        qf_inode->i_flags |= S_NOQUOTA;
+       lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA);
        err = dquot_enable(qf_inode, type, format_id, flags);
        iput(qf_inode);
+       if (err)
+               lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL);
 
        return err;
 }