|
@@ -2385,6 +2385,86 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_quota_on_mount);
|
|
|
|
|
|
+static int dquot_quota_enable(struct super_block *sb, unsigned int flags)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ int type;
|
|
|
+ struct quota_info *dqopt = sb_dqopt(sb);
|
|
|
+
|
|
|
+ if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE))
|
|
|
+ return -ENOSYS;
|
|
|
+ /* Accounting cannot be turned on while fs is mounted */
|
|
|
+ flags &= ~(FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT);
|
|
|
+ if (!flags)
|
|
|
+ return -EINVAL;
|
|
|
+ for (type = 0; type < MAXQUOTAS; type++) {
|
|
|
+ if (!(flags & qtype_enforce_flag(type)))
|
|
|
+ continue;
|
|
|
+ /* Can't enforce without accounting */
|
|
|
+ if (!sb_has_quota_usage_enabled(sb, type))
|
|
|
+ return -EINVAL;
|
|
|
+ ret = dquot_enable(dqopt->files[type], type,
|
|
|
+ dqopt->info[type].dqi_fmt_id,
|
|
|
+ DQUOT_LIMITS_ENABLED);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out_err;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+out_err:
|
|
|
+ /* Backout enforcement enablement we already did */
|
|
|
+ for (type--; type >= 0; type--) {
|
|
|
+ if (flags & qtype_enforce_flag(type))
|
|
|
+ dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
|
|
|
+ }
|
|
|
+ /* Error code translation for better compatibility with XFS */
|
|
|
+ if (ret == -EBUSY)
|
|
|
+ ret = -EEXIST;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int dquot_quota_disable(struct super_block *sb, unsigned int flags)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ int type;
|
|
|
+ struct quota_info *dqopt = sb_dqopt(sb);
|
|
|
+
|
|
|
+ if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE))
|
|
|
+ return -ENOSYS;
|
|
|
+ /*
|
|
|
+ * We don't support turning off accounting via quotactl. In principle
|
|
|
+ * quota infrastructure can do this but filesystems don't expect
|
|
|
+ * userspace to be able to do it.
|
|
|
+ */
|
|
|
+ if (flags &
|
|
|
+ (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ /* Filter out limits not enabled */
|
|
|
+ for (type = 0; type < MAXQUOTAS; type++)
|
|
|
+ if (!sb_has_quota_limits_enabled(sb, type))
|
|
|
+ flags &= ~qtype_enforce_flag(type);
|
|
|
+ /* Nothing left? */
|
|
|
+ if (!flags)
|
|
|
+ return -EEXIST;
|
|
|
+ for (type = 0; type < MAXQUOTAS; type++) {
|
|
|
+ if (flags & qtype_enforce_flag(type)) {
|
|
|
+ ret = dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out_err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+out_err:
|
|
|
+ /* Backout enforcement disabling we already did */
|
|
|
+ for (type--; type >= 0; type--) {
|
|
|
+ if (flags & qtype_enforce_flag(type))
|
|
|
+ dquot_enable(dqopt->files[type], type,
|
|
|
+ dqopt->info[type].dqi_fmt_id,
|
|
|
+ DQUOT_LIMITS_ENABLED);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static inline qsize_t qbtos(qsize_t blocks)
|
|
|
{
|
|
|
return blocks << QIF_DQBLKSIZE_BITS;
|
|
@@ -2614,6 +2694,17 @@ const struct quotactl_ops dquot_quotactl_ops = {
|
|
|
};
|
|
|
EXPORT_SYMBOL(dquot_quotactl_ops);
|
|
|
|
|
|
+const struct quotactl_ops dquot_quotactl_sysfile_ops = {
|
|
|
+ .quota_enable = dquot_quota_enable,
|
|
|
+ .quota_disable = dquot_quota_disable,
|
|
|
+ .quota_sync = dquot_quota_sync,
|
|
|
+ .get_info = dquot_get_dqinfo,
|
|
|
+ .set_info = dquot_set_dqinfo,
|
|
|
+ .get_dqblk = dquot_get_dqblk,
|
|
|
+ .set_dqblk = dquot_set_dqblk
|
|
|
+};
|
|
|
+EXPORT_SYMBOL(dquot_quotactl_sysfile_ops);
|
|
|
+
|
|
|
static int do_proc_dqstats(struct ctl_table *table, int write,
|
|
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
|
{
|