ext4: xattr inode deduplication
[linux-2.6-block.git] / fs / ext4 / super.c
index c90edf09b0c3172f94737ed1e926464fd2e8b156..d501f8256dc4640665abe9735cf5f256bdd75ae7 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/ctype.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
+#include <linux/dax.h>
 #include <linux/cleancache.h>
 #include <linux/uaccess.h>
 
@@ -847,14 +848,9 @@ static inline void ext4_quota_off_umount(struct super_block *sb)
 {
        int type;
 
-       if (ext4_has_feature_quota(sb)) {
-               dquot_disable(sb, -1,
-                             DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
-       } else {
-               /* Use our quota_off function to clear inode flags etc. */
-               for (type = 0; type < EXT4_MAXQUOTAS; type++)
-                       ext4_quota_off(sb, type);
-       }
+       /* Use our quota_off function to clear inode flags etc. */
+       for (type = 0; type < EXT4_MAXQUOTAS; type++)
+               ext4_quota_off(sb, type);
 }
 #else
 static inline void ext4_quota_off_umount(struct super_block *sb)
@@ -931,9 +927,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);
@@ -1147,7 +1147,7 @@ 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;
 
        res = ext4_convert_inline_data(inode);
        if (res)
@@ -1178,9 +1178,15 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
                return res;
        }
 
+       res = dquot_initialize(inode);
+       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, &credits);
+       if (res)
+               return res;
+
+       handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -3446,7 +3452,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.");
@@ -3468,7 +3475,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));
 
@@ -3598,6 +3605,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)) {
@@ -4062,12 +4079,21 @@ 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");
+       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)) &&
            (blocksize != PAGE_SIZE)) {
                ext4_msg(sb, KERN_ERR,
@@ -4297,9 +4323,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);
@@ -5484,7 +5514,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
                goto out;
 
        err = dquot_quota_off(sb, type);
-       if (err)
+       if (err || ext4_has_feature_quota(sb))
                goto out_put;
 
        inode_lock(inode);
@@ -5504,6 +5534,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
 out_unlock:
        inode_unlock(inode);
 out_put:
+       lockdep_set_quota_inode(inode, I_DATA_SEM_NORMAL);
        iput(inode);
        return err;
 out: