Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[linux.git] / fs / ext4 / super.c
index 18f68f09d3935bb3f6e14dd7088f4dbade390f3a..0886fe82e9c49202311922680a33723c513c9983 100644 (file)
@@ -373,6 +373,9 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
        struct ext4_journal_cb_entry    *jce;
 
        BUG_ON(txn->t_state == T_FINISHED);
+
+       ext4_process_freed_data(sb, txn->t_tid);
+
        spin_lock(&sbi->s_md_lock);
        while (!list_empty(&txn->t_private_list)) {
                jce = list_entry(txn->t_private_list.next,
@@ -927,9 +930,13 @@ static void ext4_put_super(struct super_block *sb)
                invalidate_bdev(sbi->journal_bdev);
                ext4_blkdev_remove(sbi);
        }
-       if (sbi->s_mb_cache) {
-               ext4_xattr_destroy_cache(sbi->s_mb_cache);
-               sbi->s_mb_cache = NULL;
+       if (sbi->s_ea_inode_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
+               sbi->s_ea_inode_cache = NULL;
+       }
+       if (sbi->s_ea_block_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
+               sbi->s_ea_block_cache = NULL;
        }
        if (sbi->s_mmp_tsk)
                kthread_stop(sbi->s_mmp_tsk);
@@ -1143,7 +1150,16 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
                                                        void *fs_data)
 {
        handle_t *handle = fs_data;
-       int res, res2, retries = 0;
+       int res, res2, credits, retries = 0;
+
+       /*
+        * Encrypting the root directory is not allowed because e2fsck expects
+        * lost+found to exist and be unencrypted, and encrypting the root
+        * directory would imply encrypting the lost+found directory as well as
+        * the filename "lost+found" itself.
+        */
+       if (inode->i_ino == EXT4_ROOT_INO)
+               return -EPERM;
 
        res = ext4_convert_inline_data(inode);
        if (res)
@@ -1178,8 +1194,12 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
        if (res)
                return res;
 retry:
-       handle = ext4_journal_start(inode, EXT4_HT_MISC,
-                       ext4_jbd2_credits_xattr(inode));
+       res = ext4_xattr_set_credits(inode, len, false /* is_create */,
+                                    &credits);
+       if (res)
+               return res;
+
+       handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1256,16 +1276,17 @@ static struct dquot **ext4_get_dquots(struct inode *inode)
 }
 
 static const struct dquot_operations ext4_quota_operations = {
-       .get_reserved_space = ext4_get_reserved_space,
-       .write_dquot    = ext4_write_dquot,
-       .acquire_dquot  = ext4_acquire_dquot,
-       .release_dquot  = ext4_release_dquot,
-       .mark_dirty     = ext4_mark_dquot_dirty,
-       .write_info     = ext4_write_info,
-       .alloc_dquot    = dquot_alloc,
-       .destroy_dquot  = dquot_destroy,
-       .get_projid     = ext4_get_projid,
-       .get_next_id    = ext4_get_next_id,
+       .get_reserved_space     = ext4_get_reserved_space,
+       .write_dquot            = ext4_write_dquot,
+       .acquire_dquot          = ext4_acquire_dquot,
+       .release_dquot          = ext4_release_dquot,
+       .mark_dirty             = ext4_mark_dquot_dirty,
+       .write_info             = ext4_write_info,
+       .alloc_dquot            = dquot_alloc,
+       .destroy_dquot          = dquot_destroy,
+       .get_projid             = ext4_get_projid,
+       .get_inode_usage        = ext4_get_inode_usage,
+       .get_next_id            = ext4_get_next_id,
 };
 
 static const struct quotactl_ops ext4_qctl_operations = {
@@ -1328,7 +1349,7 @@ enum {
        Opt_inode_readahead_blks, Opt_journal_ioprio,
        Opt_dioread_nolock, Opt_dioread_lock,
        Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
-       Opt_max_dir_size_kb, Opt_nojournal_checksum,
+       Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
 };
 
 static const match_table_t tokens = {
@@ -1411,6 +1432,8 @@ static const match_table_t tokens = {
        {Opt_noinit_itable, "noinit_itable"},
        {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
        {Opt_test_dummy_encryption, "test_dummy_encryption"},
+       {Opt_nombcache, "nombcache"},
+       {Opt_nombcache, "no_mbcache"},  /* for backward compatibility */
        {Opt_removed, "check=none"},    /* mount option from ext2/3 */
        {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
        {Opt_removed, "reservation"},   /* mount option from ext2/3 */
@@ -1618,6 +1641,7 @@ static const struct mount_opts {
        {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
        {Opt_max_dir_size_kb, 0, MOPT_GTE0},
        {Opt_test_dummy_encryption, 0, MOPT_GTE0},
+       {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
        {Opt_err, 0, 0}
 };
 
@@ -3445,7 +3469,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* Load the checksum driver */
-       if (ext4_has_feature_metadata_csum(sb)) {
+       if (ext4_has_feature_metadata_csum(sb) ||
+           ext4_has_feature_ea_inode(sb)) {
                sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
                if (IS_ERR(sbi->s_chksum_driver)) {
                        ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver.");
@@ -3467,7 +3492,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        /* Precompute checksum seed for all metadata */
        if (ext4_has_feature_csum_seed(sb))
                sbi->s_csum_seed = le32_to_cpu(es->s_checksum_seed);
-       else if (ext4_has_metadata_csum(sb))
+       else if (ext4_has_metadata_csum(sb) || ext4_has_feature_ea_inode(sb))
                sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
                                               sizeof(es->s_uuid));
 
@@ -3597,6 +3622,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                 "The Hurd can't support 64-bit file systems");
                        goto failed_mount;
                }
+
+               /*
+                * ea_inode feature uses l_i_version field which is not
+                * available in HURD_COMPAT mode.
+                */
+               if (ext4_has_feature_ea_inode(sb)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "ea_inode feature is not supported for Hurd");
+                       goto failed_mount;
+               }
        }
 
        if (IS_EXT2_SB(sb)) {
@@ -4061,10 +4096,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
 
 no_journal:
-       sbi->s_mb_cache = ext4_xattr_create_cache();
-       if (!sbi->s_mb_cache) {
-               ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
-               goto failed_mount_wq;
+       if (!test_opt(sb, NO_MBCACHE)) {
+               sbi->s_ea_block_cache = ext4_xattr_create_cache();
+               if (!sbi->s_ea_block_cache) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Failed to create ea_block_cache");
+                       goto failed_mount_wq;
+               }
+
+               if (ext4_has_feature_ea_inode(sb)) {
+                       sbi->s_ea_inode_cache = ext4_xattr_create_cache();
+                       if (!sbi->s_ea_inode_cache) {
+                               ext4_msg(sb, KERN_ERR,
+                                        "Failed to create ea_inode_cache");
+                               goto failed_mount_wq;
+                       }
+               }
        }
 
        if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
@@ -4296,9 +4343,13 @@ failed_mount4:
        if (EXT4_SB(sb)->rsv_conversion_wq)
                destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
 failed_mount_wq:
-       if (sbi->s_mb_cache) {
-               ext4_xattr_destroy_cache(sbi->s_mb_cache);
-               sbi->s_mb_cache = NULL;
+       if (sbi->s_ea_inode_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
+               sbi->s_ea_inode_cache = NULL;
+       }
+       if (sbi->s_ea_block_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
+               sbi->s_ea_block_cache = NULL;
        }
        if (sbi->s_journal) {
                jbd2_journal_destroy(sbi->s_journal);
@@ -4957,6 +5008,12 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                }
        }
 
+       if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_NO_MBCACHE) {
+               ext4_msg(sb, KERN_ERR, "can't enable nombcache during remount");
+               err = -EINVAL;
+               goto restore_opts;
+       }
+
        if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) {
                ext4_msg(sb, KERN_WARNING, "warning: refusing change of "
                        "dax flag with busy inodes while remounting");