diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 5 | ||||
-rw-r--r-- | fs/ext4/ext4_jbd2.h | 18 | ||||
-rw-r--r-- | fs/ext4/super.c | 137 |
3 files changed, 150 insertions, 10 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4a49f8225d0..1610e808ebe 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1315,6 +1315,8 @@ static inline struct timespec ext4_current_time(struct inode *inode) | |||
1315 | static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) | 1315 | static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) |
1316 | { | 1316 | { |
1317 | return ino == EXT4_ROOT_INO || | 1317 | return ino == EXT4_ROOT_INO || |
1318 | ino == EXT4_USR_QUOTA_INO || | ||
1319 | ino == EXT4_GRP_QUOTA_INO || | ||
1318 | ino == EXT4_JOURNAL_INO || | 1320 | ino == EXT4_JOURNAL_INO || |
1319 | ino == EXT4_RESIZE_INO || | 1321 | ino == EXT4_RESIZE_INO || |
1320 | (ino >= EXT4_FIRST_INO(sb) && | 1322 | (ino >= EXT4_FIRST_INO(sb) && |
@@ -1497,7 +1499,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) | |||
1497 | EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\ | 1499 | EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\ |
1498 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\ | 1500 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\ |
1499 | EXT4_FEATURE_RO_COMPAT_BIGALLOC |\ | 1501 | EXT4_FEATURE_RO_COMPAT_BIGALLOC |\ |
1500 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) | 1502 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ |
1503 | EXT4_FEATURE_RO_COMPAT_QUOTA) | ||
1501 | 1504 | ||
1502 | /* | 1505 | /* |
1503 | * Default values for user and/or group using reserved blocks | 1506 | * Default values for user and/or group using reserved blocks |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index f440e8f1841..1393c830411 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -87,14 +87,20 @@ | |||
87 | #ifdef CONFIG_QUOTA | 87 | #ifdef CONFIG_QUOTA |
88 | /* Amount of blocks needed for quota update - we know that the structure was | 88 | /* Amount of blocks needed for quota update - we know that the structure was |
89 | * allocated so we need to update only data block */ | 89 | * allocated so we need to update only data block */ |
90 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 1 : 0) | 90 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\ |
91 | EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\ | ||
92 | 1 : 0) | ||
91 | /* Amount of blocks needed for quota insert/delete - we do some block writes | 93 | /* Amount of blocks needed for quota insert/delete - we do some block writes |
92 | * but inode, sb and group updates are done only once */ | 94 | * but inode, sb and group updates are done only once */ |
93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ | 95 | #define EXT4_QUOTA_INIT_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\ |
94 | (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0) | 96 | EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\ |
95 | 97 | (DQUOT_INIT_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\ | |
96 | #define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ | 98 | +3+DQUOT_INIT_REWRITE) : 0) |
97 | (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0) | 99 | |
100 | #define EXT4_QUOTA_DEL_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\ | ||
101 | EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\ | ||
102 | (DQUOT_DEL_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\ | ||
103 | +3+DQUOT_DEL_REWRITE) : 0) | ||
98 | #else | 104 | #else |
99 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 | 105 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 |
100 | #define EXT4_QUOTA_INIT_BLOCKS(sb) 0 | 106 | #define EXT4_QUOTA_INIT_BLOCKS(sb) 0 |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 78b7ede2efa..bebf8e5bf08 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -1137,12 +1137,18 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot); | |||
1137 | static int ext4_write_info(struct super_block *sb, int type); | 1137 | static int ext4_write_info(struct super_block *sb, int type); |
1138 | static int ext4_quota_on(struct super_block *sb, int type, int format_id, | 1138 | static int ext4_quota_on(struct super_block *sb, int type, int format_id, |
1139 | struct path *path); | 1139 | struct path *path); |
1140 | static int ext4_quota_on_sysfile(struct super_block *sb, int type, | ||
1141 | int format_id); | ||
1140 | static int ext4_quota_off(struct super_block *sb, int type); | 1142 | static int ext4_quota_off(struct super_block *sb, int type); |
1143 | static int ext4_quota_off_sysfile(struct super_block *sb, int type); | ||
1141 | static int ext4_quota_on_mount(struct super_block *sb, int type); | 1144 | static int ext4_quota_on_mount(struct super_block *sb, int type); |
1142 | static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, | 1145 | static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, |
1143 | size_t len, loff_t off); | 1146 | size_t len, loff_t off); |
1144 | static ssize_t ext4_quota_write(struct super_block *sb, int type, | 1147 | static ssize_t ext4_quota_write(struct super_block *sb, int type, |
1145 | const char *data, size_t len, loff_t off); | 1148 | const char *data, size_t len, loff_t off); |
1149 | static int ext4_quota_enable(struct super_block *sb, int type, int format_id, | ||
1150 | unsigned int flags); | ||
1151 | static int ext4_enable_quotas(struct super_block *sb); | ||
1146 | 1152 | ||
1147 | static const struct dquot_operations ext4_quota_operations = { | 1153 | static const struct dquot_operations ext4_quota_operations = { |
1148 | .get_reserved_space = ext4_get_reserved_space, | 1154 | .get_reserved_space = ext4_get_reserved_space, |
@@ -1164,6 +1170,16 @@ static const struct quotactl_ops ext4_qctl_operations = { | |||
1164 | .get_dqblk = dquot_get_dqblk, | 1170 | .get_dqblk = dquot_get_dqblk, |
1165 | .set_dqblk = dquot_set_dqblk | 1171 | .set_dqblk = dquot_set_dqblk |
1166 | }; | 1172 | }; |
1173 | |||
1174 | static const struct quotactl_ops ext4_qctl_sysfile_operations = { | ||
1175 | .quota_on_meta = ext4_quota_on_sysfile, | ||
1176 | .quota_off = ext4_quota_off_sysfile, | ||
1177 | .quota_sync = dquot_quota_sync, | ||
1178 | .get_info = dquot_get_dqinfo, | ||
1179 | .set_info = dquot_set_dqinfo, | ||
1180 | .get_dqblk = dquot_get_dqblk, | ||
1181 | .set_dqblk = dquot_set_dqblk | ||
1182 | }; | ||
1167 | #endif | 1183 | #endif |
1168 | 1184 | ||
1169 | static const struct super_operations ext4_sops = { | 1185 | static const struct super_operations ext4_sops = { |
@@ -2661,6 +2677,16 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly) | |||
2661 | "extents feature\n"); | 2677 | "extents feature\n"); |
2662 | return 0; | 2678 | return 0; |
2663 | } | 2679 | } |
2680 | |||
2681 | #ifndef CONFIG_QUOTA | ||
2682 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) && | ||
2683 | !readonly) { | ||
2684 | ext4_msg(sb, KERN_ERR, | ||
2685 | "Filesystem with quota feature cannot be mounted RDWR " | ||
2686 | "without CONFIG_QUOTA"); | ||
2687 | return 0; | ||
2688 | } | ||
2689 | #endif /* CONFIG_QUOTA */ | ||
2664 | return 1; | 2690 | return 1; |
2665 | } | 2691 | } |
2666 | 2692 | ||
@@ -3748,6 +3774,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3748 | #ifdef CONFIG_QUOTA | 3774 | #ifdef CONFIG_QUOTA |
3749 | sb->s_qcop = &ext4_qctl_operations; | 3775 | sb->s_qcop = &ext4_qctl_operations; |
3750 | sb->dq_op = &ext4_quota_operations; | 3776 | sb->dq_op = &ext4_quota_operations; |
3777 | |||
3778 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) { | ||
3779 | /* Use qctl operations for hidden quota files. */ | ||
3780 | sb->s_qcop = &ext4_qctl_sysfile_operations; | ||
3781 | } | ||
3751 | #endif | 3782 | #endif |
3752 | memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); | 3783 | memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); |
3753 | 3784 | ||
@@ -3960,6 +3991,16 @@ no_journal: | |||
3960 | } else | 3991 | } else |
3961 | descr = "out journal"; | 3992 | descr = "out journal"; |
3962 | 3993 | ||
3994 | #ifdef CONFIG_QUOTA | ||
3995 | /* Enable quota usage during mount. */ | ||
3996 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) && | ||
3997 | !(sb->s_flags & MS_RDONLY)) { | ||
3998 | ret = ext4_enable_quotas(sb); | ||
3999 | if (ret) | ||
4000 | goto failed_mount7; | ||
4001 | } | ||
4002 | #endif /* CONFIG_QUOTA */ | ||
4003 | |||
3963 | ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. " | 4004 | ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. " |
3964 | "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, | 4005 | "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, |
3965 | *sbi->s_es->s_mount_opts ? "; " : "", orig_data); | 4006 | *sbi->s_es->s_mount_opts ? "; " : "", orig_data); |
@@ -4682,16 +4723,26 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
4682 | if (sbi->s_journal == NULL) | 4723 | if (sbi->s_journal == NULL) |
4683 | ext4_commit_super(sb, 1); | 4724 | ext4_commit_super(sb, 1); |
4684 | 4725 | ||
4726 | unlock_super(sb); | ||
4685 | #ifdef CONFIG_QUOTA | 4727 | #ifdef CONFIG_QUOTA |
4686 | /* Release old quota file names */ | 4728 | /* Release old quota file names */ |
4687 | for (i = 0; i < MAXQUOTAS; i++) | 4729 | for (i = 0; i < MAXQUOTAS; i++) |
4688 | if (old_opts.s_qf_names[i] && | 4730 | if (old_opts.s_qf_names[i] && |
4689 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) | 4731 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) |
4690 | kfree(old_opts.s_qf_names[i]); | 4732 | kfree(old_opts.s_qf_names[i]); |
4733 | if (enable_quota) { | ||
4734 | if (sb_any_quota_suspended(sb)) | ||
4735 | dquot_resume(sb, -1); | ||
4736 | else if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
4737 | EXT4_FEATURE_RO_COMPAT_QUOTA)) { | ||
4738 | err = ext4_enable_quotas(sb); | ||
4739 | if (err) { | ||
4740 | lock_super(sb); | ||
4741 | goto restore_opts; | ||
4742 | } | ||
4743 | } | ||
4744 | } | ||
4691 | #endif | 4745 | #endif |
4692 | unlock_super(sb); | ||
4693 | if (enable_quota) | ||
4694 | dquot_resume(sb, -1); | ||
4695 | 4746 | ||
4696 | ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data); | 4747 | ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data); |
4697 | kfree(orig_data); | 4748 | kfree(orig_data); |
@@ -4904,6 +4955,74 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
4904 | return dquot_quota_on(sb, type, format_id, path); | 4955 | return dquot_quota_on(sb, type, format_id, path); |
4905 | } | 4956 | } |
4906 | 4957 | ||
4958 | static int ext4_quota_enable(struct super_block *sb, int type, int format_id, | ||
4959 | unsigned int flags) | ||
4960 | { | ||
4961 | int err; | ||
4962 | struct inode *qf_inode; | ||
4963 | unsigned long qf_inums[MAXQUOTAS] = { | ||
4964 | le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | ||
4965 | le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum) | ||
4966 | }; | ||
4967 | |||
4968 | BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)); | ||
4969 | |||
4970 | if (!qf_inums[type]) | ||
4971 | return -EPERM; | ||
4972 | |||
4973 | qf_inode = ext4_iget(sb, qf_inums[type]); | ||
4974 | if (IS_ERR(qf_inode)) { | ||
4975 | ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]); | ||
4976 | return PTR_ERR(qf_inode); | ||
4977 | } | ||
4978 | |||
4979 | err = dquot_enable(qf_inode, type, format_id, flags); | ||
4980 | iput(qf_inode); | ||
4981 | |||
4982 | return err; | ||
4983 | } | ||
4984 | |||
4985 | /* Enable usage tracking for all quota types. */ | ||
4986 | static int ext4_enable_quotas(struct super_block *sb) | ||
4987 | { | ||
4988 | int type, err = 0; | ||
4989 | unsigned long qf_inums[MAXQUOTAS] = { | ||
4990 | le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | ||
4991 | le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum) | ||
4992 | }; | ||
4993 | |||
4994 | sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; | ||
4995 | for (type = 0; type < MAXQUOTAS; type++) { | ||
4996 | if (qf_inums[type]) { | ||
4997 | err = ext4_quota_enable(sb, type, QFMT_VFS_V1, | ||
4998 | DQUOT_USAGE_ENABLED); | ||
4999 | if (err) { | ||
5000 | ext4_warning(sb, | ||
5001 | "Failed to enable quota (type=%d) " | ||
5002 | "tracking. Please run e2fsck to fix.", | ||
5003 | type); | ||
5004 | return err; | ||
5005 | } | ||
5006 | } | ||
5007 | } | ||
5008 | return 0; | ||
5009 | } | ||
5010 | |||
5011 | /* | ||
5012 | * quota_on function that is used when QUOTA feature is set. | ||
5013 | */ | ||
5014 | static int ext4_quota_on_sysfile(struct super_block *sb, int type, | ||
5015 | int format_id) | ||
5016 | { | ||
5017 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) | ||
5018 | return -EINVAL; | ||
5019 | |||
5020 | /* | ||
5021 | * USAGE was enabled at mount time. Only need to enable LIMITS now. | ||
5022 | */ | ||
5023 | return ext4_quota_enable(sb, type, format_id, DQUOT_LIMITS_ENABLED); | ||
5024 | } | ||
5025 | |||
4907 | static int ext4_quota_off(struct super_block *sb, int type) | 5026 | static int ext4_quota_off(struct super_block *sb, int type) |
4908 | { | 5027 | { |
4909 | struct inode *inode = sb_dqopt(sb)->files[type]; | 5028 | struct inode *inode = sb_dqopt(sb)->files[type]; |
@@ -4930,6 +5049,18 @@ out: | |||
4930 | return dquot_quota_off(sb, type); | 5049 | return dquot_quota_off(sb, type); |
4931 | } | 5050 | } |
4932 | 5051 | ||
5052 | /* | ||
5053 | * quota_off function that is used when QUOTA feature is set. | ||
5054 | */ | ||
5055 | static int ext4_quota_off_sysfile(struct super_block *sb, int type) | ||
5056 | { | ||
5057 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) | ||
5058 | return -EINVAL; | ||
5059 | |||
5060 | /* Disable only the limits. */ | ||
5061 | return dquot_disable(sb, type, DQUOT_LIMITS_ENABLED); | ||
5062 | } | ||
5063 | |||
4933 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 5064 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
4934 | * acquiring the locks... As quota files are never truncated and quota code | 5065 | * acquiring the locks... As quota files are never truncated and quota code |
4935 | * itself serializes the operations (and no one else should touch the files) | 5066 | * itself serializes the operations (and no one else should touch the files) |