quota: Add ->quota_{enable,disable} callbacks for VFS quotas
Add functions which translate ->quota_enable / ->quota_disable calls into appropriate changes in VFS quota. This will enable filesystems supporting VFS quota files in system inodes to be controlled via Q_XQUOTA[ON|OFF] quotactls for better userspace compatibility. Also provide a vector for quotactl using these functions which can be used by filesystems with quota files stored in hidden system files. Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
d3b8632485
commit
3e2af67e66
@ -2385,6 +2385,86 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dquot_quota_on_mount);
|
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)
|
static inline qsize_t qbtos(qsize_t blocks)
|
||||||
{
|
{
|
||||||
return blocks << QIF_DQBLKSIZE_BITS;
|
return blocks << QIF_DQBLKSIZE_BITS;
|
||||||
@ -2614,6 +2694,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)
|
||||||
{
|
{
|
||||||
|
@ -166,6 +166,7 @@ static inline bool sb_has_quota_active(struct super_block *sb, int type)
|
|||||||
*/
|
*/
|
||||||
extern const struct dquot_operations dquot_operations;
|
extern const struct dquot_operations dquot_operations;
|
||||||
extern const struct quotactl_ops dquot_quotactl_ops;
|
extern const struct quotactl_ops dquot_quotactl_ops;
|
||||||
|
extern const struct quotactl_ops dquot_quotactl_sysfile_ops;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user