quota: Hook up Q_XSETQLIM for id 0 to ->set_info
Setting timers or warning counts for id 0 via Q_XSETQLIM is used to actually set time limits and warning limits for all users. Hook up ->set_info to this so that VFS quota time limits get set the same way as XFS ones. When doing this Q_XSETQLIM for XFS is effectively split into two independent transactions - one for setting timers and warning limits and one for setting space and inode limits. Although this is inefficient, it is rare enough that it does not matter. Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Родитель
c14cad9eed
Коммит
c39fb53b48
|
@ -517,6 +517,30 @@ static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
|
|||
dst->d_fieldmask |= QC_RT_SPACE;
|
||||
}
|
||||
|
||||
static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst,
|
||||
struct fs_disk_quota *src)
|
||||
{
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
dst->i_spc_timelimit = src->d_btimer;
|
||||
dst->i_ino_timelimit = src->d_itimer;
|
||||
dst->i_rt_spc_timelimit = src->d_rtbtimer;
|
||||
dst->i_ino_warnlimit = src->d_iwarns;
|
||||
dst->i_spc_warnlimit = src->d_bwarns;
|
||||
dst->i_rt_spc_warnlimit = src->d_rtbwarns;
|
||||
if (src->d_fieldmask & FS_DQ_BWARNS)
|
||||
dst->i_fieldmask |= QC_SPC_WARNS;
|
||||
if (src->d_fieldmask & FS_DQ_IWARNS)
|
||||
dst->i_fieldmask |= QC_INO_WARNS;
|
||||
if (src->d_fieldmask & FS_DQ_RTBWARNS)
|
||||
dst->i_fieldmask |= QC_RT_SPC_WARNS;
|
||||
if (src->d_fieldmask & FS_DQ_BTIMER)
|
||||
dst->i_fieldmask |= QC_SPC_TIMER;
|
||||
if (src->d_fieldmask & FS_DQ_ITIMER)
|
||||
dst->i_fieldmask |= QC_INO_TIMER;
|
||||
if (src->d_fieldmask & FS_DQ_RTBTIMER)
|
||||
dst->i_fieldmask |= QC_RT_SPC_TIMER;
|
||||
}
|
||||
|
||||
static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
||||
void __user *addr)
|
||||
{
|
||||
|
@ -531,6 +555,21 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
|||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
return -EINVAL;
|
||||
/* Are we actually setting timer / warning limits for all users? */
|
||||
if (from_kqid(&init_user_ns, qid) == 0 &&
|
||||
fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) {
|
||||
struct qc_info qinfo;
|
||||
int ret;
|
||||
|
||||
if (!sb->s_qcop->set_info)
|
||||
return -EINVAL;
|
||||
copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq);
|
||||
ret = sb->s_qcop->set_info(sb, type, &qinfo);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* These are already done */
|
||||
fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK);
|
||||
}
|
||||
copy_from_xfs_dqblk(&qdq, &fdq);
|
||||
return sb->s_qcop->set_dqblk(sb, qid, &qdq);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче