diff options
author | Li Xi <pkuelelixi@gmail.com> | 2016-01-08 16:01:22 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-01-08 16:01:22 -0500 |
commit | 689c958cbe6be4f211b40747951a3ba2c73b6715 (patch) | |
tree | ae9ae7fa7fe607d9dede6a221cb5c2660a7b3de1 /fs | |
parent | 040cb3786d9b25293b8b0b05b90da0f871e1eb9b (diff) |
ext4: add project quota support
This patch adds mount options for enabling/disabling project quota
accounting and enforcement. A new specific inode is also used for
project quota accounting.
[ Includes fix from Dan Carpenter to crrect error checking from dqget(). ]
Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 2 | ||||
-rw-r--r-- | fs/ext4/super.c | 65 |
2 files changed, 61 insertions, 6 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 023781101bae..96cc151d5931 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1261,7 +1261,7 @@ struct ext4_super_block { | |||
1261 | #endif | 1261 | #endif |
1262 | 1262 | ||
1263 | /* Number of quota types we support */ | 1263 | /* Number of quota types we support */ |
1264 | #define EXT4_MAXQUOTAS 2 | 1264 | #define EXT4_MAXQUOTAS 3 |
1265 | 1265 | ||
1266 | /* | 1266 | /* |
1267 | * fourth extended-fs super-block data in memory | 1267 | * fourth extended-fs super-block data in memory |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 844c95d95821..3aea58a7ea8f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -1097,8 +1097,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page, | |||
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | #ifdef CONFIG_QUOTA | 1099 | #ifdef CONFIG_QUOTA |
1100 | #define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group") | 1100 | static char *quotatypes[] = INITQFNAMES; |
1101 | #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) | 1101 | #define QTYPE2NAME(t) (quotatypes[t]) |
1102 | 1102 | ||
1103 | static int ext4_write_dquot(struct dquot *dquot); | 1103 | static int ext4_write_dquot(struct dquot *dquot); |
1104 | static int ext4_acquire_dquot(struct dquot *dquot); | 1104 | static int ext4_acquire_dquot(struct dquot *dquot); |
@@ -2558,6 +2558,12 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly) | |||
2558 | "without CONFIG_QUOTA"); | 2558 | "without CONFIG_QUOTA"); |
2559 | return 0; | 2559 | return 0; |
2560 | } | 2560 | } |
2561 | if (ext4_has_feature_project(sb) && !readonly) { | ||
2562 | ext4_msg(sb, KERN_ERR, | ||
2563 | "Filesystem with project quota feature cannot be mounted RDWR " | ||
2564 | "without CONFIG_QUOTA"); | ||
2565 | return 0; | ||
2566 | } | ||
2561 | #endif /* CONFIG_QUOTA */ | 2567 | #endif /* CONFIG_QUOTA */ |
2562 | return 1; | 2568 | return 1; |
2563 | } | 2569 | } |
@@ -3686,7 +3692,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3686 | sb->s_qcop = &dquot_quotactl_sysfile_ops; | 3692 | sb->s_qcop = &dquot_quotactl_sysfile_ops; |
3687 | else | 3693 | else |
3688 | sb->s_qcop = &ext4_qctl_operations; | 3694 | sb->s_qcop = &ext4_qctl_operations; |
3689 | sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; | 3695 | sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; |
3690 | #endif | 3696 | #endif |
3691 | memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); | 3697 | memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); |
3692 | 3698 | ||
@@ -4822,6 +4828,48 @@ restore_opts: | |||
4822 | return err; | 4828 | return err; |
4823 | } | 4829 | } |
4824 | 4830 | ||
4831 | #ifdef CONFIG_QUOTA | ||
4832 | static int ext4_statfs_project(struct super_block *sb, | ||
4833 | kprojid_t projid, struct kstatfs *buf) | ||
4834 | { | ||
4835 | struct kqid qid; | ||
4836 | struct dquot *dquot; | ||
4837 | u64 limit; | ||
4838 | u64 curblock; | ||
4839 | |||
4840 | qid = make_kqid_projid(projid); | ||
4841 | dquot = dqget(sb, qid); | ||
4842 | if (IS_ERR(dquot)) | ||
4843 | return PTR_ERR(dquot); | ||
4844 | spin_lock(&dq_data_lock); | ||
4845 | |||
4846 | limit = (dquot->dq_dqb.dqb_bsoftlimit ? | ||
4847 | dquot->dq_dqb.dqb_bsoftlimit : | ||
4848 | dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits; | ||
4849 | if (limit && buf->f_blocks > limit) { | ||
4850 | curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits; | ||
4851 | buf->f_blocks = limit; | ||
4852 | buf->f_bfree = buf->f_bavail = | ||
4853 | (buf->f_blocks > curblock) ? | ||
4854 | (buf->f_blocks - curblock) : 0; | ||
4855 | } | ||
4856 | |||
4857 | limit = dquot->dq_dqb.dqb_isoftlimit ? | ||
4858 | dquot->dq_dqb.dqb_isoftlimit : | ||
4859 | dquot->dq_dqb.dqb_ihardlimit; | ||
4860 | if (limit && buf->f_files > limit) { | ||
4861 | buf->f_files = limit; | ||
4862 | buf->f_ffree = | ||
4863 | (buf->f_files > dquot->dq_dqb.dqb_curinodes) ? | ||
4864 | (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0; | ||
4865 | } | ||
4866 | |||
4867 | spin_unlock(&dq_data_lock); | ||
4868 | dqput(dquot); | ||
4869 | return 0; | ||
4870 | } | ||
4871 | #endif | ||
4872 | |||
4825 | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | 4873 | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) |
4826 | { | 4874 | { |
4827 | struct super_block *sb = dentry->d_sb; | 4875 | struct super_block *sb = dentry->d_sb; |
@@ -4854,6 +4902,11 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
4854 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; | 4902 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; |
4855 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; | 4903 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; |
4856 | 4904 | ||
4905 | #ifdef CONFIG_QUOTA | ||
4906 | if (ext4_test_inode_flag(dentry->d_inode, EXT4_INODE_PROJINHERIT) && | ||
4907 | sb_has_quota_limits_enabled(sb, PRJQUOTA)) | ||
4908 | ext4_statfs_project(sb, EXT4_I(dentry->d_inode)->i_projid, buf); | ||
4909 | #endif | ||
4857 | return 0; | 4910 | return 0; |
4858 | } | 4911 | } |
4859 | 4912 | ||
@@ -5018,7 +5071,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id, | |||
5018 | struct inode *qf_inode; | 5071 | struct inode *qf_inode; |
5019 | unsigned long qf_inums[EXT4_MAXQUOTAS] = { | 5072 | unsigned long qf_inums[EXT4_MAXQUOTAS] = { |
5020 | le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | 5073 | le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), |
5021 | le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum) | 5074 | le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), |
5075 | le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) | ||
5022 | }; | 5076 | }; |
5023 | 5077 | ||
5024 | BUG_ON(!ext4_has_feature_quota(sb)); | 5078 | BUG_ON(!ext4_has_feature_quota(sb)); |
@@ -5046,7 +5100,8 @@ static int ext4_enable_quotas(struct super_block *sb) | |||
5046 | int type, err = 0; | 5100 | int type, err = 0; |
5047 | unsigned long qf_inums[EXT4_MAXQUOTAS] = { | 5101 | unsigned long qf_inums[EXT4_MAXQUOTAS] = { |
5048 | le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | 5102 | le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), |
5049 | le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum) | 5103 | le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), |
5104 | le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) | ||
5050 | }; | 5105 | }; |
5051 | 5106 | ||
5052 | sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; | 5107 | sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; |