diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 388b6bcd..111ac5e1 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1485,6 +1485,8 @@ struct ext4_sb_info { struct ratelimit_state s_warning_ratelimit_state; struct ratelimit_state s_msg_ratelimit_state; struct dax_device *s_daxdev; + + bool s_proj_kernel_supported; }; static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index e6566eb9..ac0dd4a7 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4390,6 +4390,17 @@ int ext4_get_projid(struct inode *inode, kprojid_t *projid) { struct ext4_super_block *sbi = EXT4_SB(inode->i_sb)->s_es; + /* + * This is tricky and just used to detect whether kernel + * supports project quota, return error to make sure dquot_initialize() + * doesn't do anything except calling this function. + */ + if (inode->i_ino == EXT4_ROOT_INO && + !EXT4_SB(inode->i_sb)->s_proj_kernel_supported) { + EXT4_SB(inode->i_sb)->s_proj_kernel_supported = true; + return -EINVAL; + } + if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_RO_COMPAT_PROJECT) && !sbi->s_prj_quota_inum) return -EOPNOTSUPP; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1c81d178..bb92ea94 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -819,8 +819,11 @@ static inline void ext4_quota_off_umount(struct super_block *sb) int type; /* Use our quota_off function to clear inode flags etc. */ - for (type = 0; type < EXT4_MAXQUOTAS; type++) + for (type = 0; type < EXT4_MAXQUOTAS; type++) { + if (!EXT4_SB(sb)->s_proj_kernel_supported && type == PRJQUOTA) + continue; ext4_quota_off(sb, type); + } } #else static inline void ext4_quota_off_umount(struct super_block *sb) @@ -2430,6 +2433,9 @@ static void ext4_orphan_cleanup(struct super_block *sb, /* Turn off quotas if they were enabled for orphan cleanup */ if (quota_update) { for (i = 0; i < EXT4_MAXQUOTAS; i++) { + if (!EXT4_SB(sb)->s_proj_kernel_supported && + i == PRJQUOTA) + continue; if (sb_dqopt(sb)->files[i]) dquot_quota_off(sb, i); } @@ -3630,6 +3636,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) int err = 0; unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; ext4_group_t first_not_zeroed; + unsigned int quota_flags; if ((data && !orig_data) || !sbi) goto out_free_base; @@ -4356,6 +4363,14 @@ no_journal: root = NULL; goto failed_mount4; } + /* + * Enable project usage temporarily to give dquota_initialize() a + * chance to check whether kernel supports Project quota. + */ + quota_flags = sb_dqopt(sb)->flags; + sb_dqopt(sb)->flags |= dquot_state_flag(DQUOT_USAGE_ENABLED, PRJQUOTA); + dquot_initialize(root); + sb_dqopt(sb)->flags = quota_flags; if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck"); iput(root); @@ -5671,6 +5686,10 @@ static int ext4_enable_quotas(struct super_block *sb) sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; for (type = 0; type < EXT4_MAXQUOTAS; type++) { + + if (!EXT4_SB(sb)->s_proj_kernel_supported && type == PRJQUOTA) + continue; + if (qf_inums[type]) { err = ext4_quota_enable(sb, type, QFMT_VFS_V1, DQUOT_USAGE_ENABLED);