|
@@ -1248,7 +1248,7 @@ static int ignore_hardlimit(struct dquot *dquot)
|
|
|
|
|
|
return capable(CAP_SYS_RESOURCE) &&
|
|
return capable(CAP_SYS_RESOURCE) &&
|
|
(info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
|
|
(info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
|
|
- !(info->dqi_flags & V1_DQF_RSQUASH));
|
|
|
|
|
|
+ !(info->dqi_flags & DQF_ROOT_SQUASH));
|
|
}
|
|
}
|
|
|
|
|
|
/* needs dq_data_lock */
|
|
/* needs dq_data_lock */
|
|
@@ -2385,14 +2385,84 @@ out:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(dquot_quota_on_mount);
|
|
EXPORT_SYMBOL(dquot_quota_on_mount);
|
|
|
|
|
|
-static inline qsize_t qbtos(qsize_t blocks)
|
|
|
|
|
|
+static int dquot_quota_enable(struct super_block *sb, unsigned int flags)
|
|
{
|
|
{
|
|
- return blocks << QIF_DQBLKSIZE_BITS;
|
|
|
|
|
|
+ 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 inline qsize_t stoqb(qsize_t space)
|
|
|
|
|
|
+static int dquot_quota_disable(struct super_block *sb, unsigned int flags)
|
|
{
|
|
{
|
|
- return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
|
|
|
|
|
|
+ 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;
|
|
}
|
|
}
|
|
|
|
|
|
/* Generic routine for getting common part of quota structure */
|
|
/* Generic routine for getting common part of quota structure */
|
|
@@ -2444,13 +2514,13 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
if (((di->d_fieldmask & QC_SPC_SOFT) &&
|
|
if (((di->d_fieldmask & QC_SPC_SOFT) &&
|
|
- stoqb(di->d_spc_softlimit) > dqi->dqi_maxblimit) ||
|
|
|
|
|
|
+ di->d_spc_softlimit > dqi->dqi_max_spc_limit) ||
|
|
((di->d_fieldmask & QC_SPC_HARD) &&
|
|
((di->d_fieldmask & QC_SPC_HARD) &&
|
|
- stoqb(di->d_spc_hardlimit) > dqi->dqi_maxblimit) ||
|
|
|
|
|
|
+ di->d_spc_hardlimit > dqi->dqi_max_spc_limit) ||
|
|
((di->d_fieldmask & QC_INO_SOFT) &&
|
|
((di->d_fieldmask & QC_INO_SOFT) &&
|
|
- (di->d_ino_softlimit > dqi->dqi_maxilimit)) ||
|
|
|
|
|
|
+ (di->d_ino_softlimit > dqi->dqi_max_ino_limit)) ||
|
|
((di->d_fieldmask & QC_INO_HARD) &&
|
|
((di->d_fieldmask & QC_INO_HARD) &&
|
|
- (di->d_ino_hardlimit > dqi->dqi_maxilimit)))
|
|
|
|
|
|
+ (di->d_ino_hardlimit > dqi->dqi_max_ino_limit)))
|
|
return -ERANGE;
|
|
return -ERANGE;
|
|
|
|
|
|
spin_lock(&dq_data_lock);
|
|
spin_lock(&dq_data_lock);
|
|
@@ -2577,6 +2647,14 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
mi = sb_dqopt(sb)->info + type;
|
|
mi = sb_dqopt(sb)->info + type;
|
|
|
|
+ if (ii->dqi_valid & IIF_FLAGS) {
|
|
|
|
+ if (ii->dqi_flags & ~DQF_SETINFO_MASK ||
|
|
|
|
+ (ii->dqi_flags & DQF_ROOT_SQUASH &&
|
|
|
|
+ mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) {
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
spin_lock(&dq_data_lock);
|
|
spin_lock(&dq_data_lock);
|
|
if (ii->dqi_valid & IIF_BGRACE)
|
|
if (ii->dqi_valid & IIF_BGRACE)
|
|
mi->dqi_bgrace = ii->dqi_bgrace;
|
|
mi->dqi_bgrace = ii->dqi_bgrace;
|
|
@@ -2606,6 +2684,17 @@ const struct quotactl_ops dquot_quotactl_ops = {
|
|
};
|
|
};
|
|
EXPORT_SYMBOL(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,
|
|
static int do_proc_dqstats(struct ctl_table *table, int write,
|
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
{
|
|
{
|