diff options
author | Jan Kara <jack@suse.cz> | 2014-12-16 10:12:27 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2015-03-04 10:06:39 -0500 |
commit | c39fb53b48c851b185c22548153581d78f2acc11 (patch) | |
tree | 9cb77c6c41e412eae92f26c8528e65b35c9ec703 /fs/quota | |
parent | c14cad9eed11343014f73aae4a77278239b201b8 (diff) |
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>
Diffstat (limited to 'fs/quota')
-rw-r--r-- | fs/quota/quota.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 741d5a178268..86ded7375c21 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
@@ -517,6 +517,30 @@ static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src) | |||
517 | dst->d_fieldmask |= QC_RT_SPACE; | 517 | dst->d_fieldmask |= QC_RT_SPACE; |
518 | } | 518 | } |
519 | 519 | ||
520 | static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst, | ||
521 | struct fs_disk_quota *src) | ||
522 | { | ||
523 | memset(dst, 0, sizeof(*dst)); | ||
524 | dst->i_spc_timelimit = src->d_btimer; | ||
525 | dst->i_ino_timelimit = src->d_itimer; | ||
526 | dst->i_rt_spc_timelimit = src->d_rtbtimer; | ||
527 | dst->i_ino_warnlimit = src->d_iwarns; | ||
528 | dst->i_spc_warnlimit = src->d_bwarns; | ||
529 | dst->i_rt_spc_warnlimit = src->d_rtbwarns; | ||
530 | if (src->d_fieldmask & FS_DQ_BWARNS) | ||
531 | dst->i_fieldmask |= QC_SPC_WARNS; | ||
532 | if (src->d_fieldmask & FS_DQ_IWARNS) | ||
533 | dst->i_fieldmask |= QC_INO_WARNS; | ||
534 | if (src->d_fieldmask & FS_DQ_RTBWARNS) | ||
535 | dst->i_fieldmask |= QC_RT_SPC_WARNS; | ||
536 | if (src->d_fieldmask & FS_DQ_BTIMER) | ||
537 | dst->i_fieldmask |= QC_SPC_TIMER; | ||
538 | if (src->d_fieldmask & FS_DQ_ITIMER) | ||
539 | dst->i_fieldmask |= QC_INO_TIMER; | ||
540 | if (src->d_fieldmask & FS_DQ_RTBTIMER) | ||
541 | dst->i_fieldmask |= QC_RT_SPC_TIMER; | ||
542 | } | ||
543 | |||
520 | static int quota_setxquota(struct super_block *sb, int type, qid_t id, | 544 | static int quota_setxquota(struct super_block *sb, int type, qid_t id, |
521 | void __user *addr) | 545 | void __user *addr) |
522 | { | 546 | { |
@@ -531,6 +555,21 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id, | |||
531 | qid = make_kqid(current_user_ns(), type, id); | 555 | qid = make_kqid(current_user_ns(), type, id); |
532 | if (!qid_valid(qid)) | 556 | if (!qid_valid(qid)) |
533 | return -EINVAL; | 557 | return -EINVAL; |
558 | /* Are we actually setting timer / warning limits for all users? */ | ||
559 | if (from_kqid(&init_user_ns, qid) == 0 && | ||
560 | fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) { | ||
561 | struct qc_info qinfo; | ||
562 | int ret; | ||
563 | |||
564 | if (!sb->s_qcop->set_info) | ||
565 | return -EINVAL; | ||
566 | copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq); | ||
567 | ret = sb->s_qcop->set_info(sb, type, &qinfo); | ||
568 | if (ret) | ||
569 | return ret; | ||
570 | /* These are already done */ | ||
571 | fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK); | ||
572 | } | ||
534 | copy_from_xfs_dqblk(&qdq, &fdq); | 573 | copy_from_xfs_dqblk(&qdq, &fdq); |
535 | return sb->s_qcop->set_dqblk(sb, qid, &qdq); | 574 | return sb->s_qcop->set_dqblk(sb, qid, &qdq); |
536 | } | 575 | } |