aboutsummaryrefslogtreecommitdiffstats
path: root/fs/quota
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-12-16 10:12:27 -0500
committerJan Kara <jack@suse.cz>2015-03-04 10:06:39 -0500
commitc39fb53b48c851b185c22548153581d78f2acc11 (patch)
tree9cb77c6c41e412eae92f26c8528e65b35c9ec703 /fs/quota
parentc14cad9eed11343014f73aae4a77278239b201b8 (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.c39
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
520static 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
520static int quota_setxquota(struct super_block *sb, int type, qid_t id, 544static 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}