quota: Switch ->get_dqblk() and ->set_dqblk() to use bytes as space units
Currently ->get_dqblk() and ->set_dqblk() use struct fs_disk_quota which tracks space limits and usage in 512-byte blocks. However VFS quotas track usage in bytes (as some filesystems require that) and we need to somehow pass this information. Upto now it wasn't a problem because we didn't do any unit conversion (thus VFS quota routines happily stuck number of bytes into d_bcount field of struct fd_disk_quota). Only if you tried to use Q_XGETQUOTA or Q_XSETQLIM for VFS quotas (or Q_GETQUOTA / Q_SETQUOTA for XFS quotas), you got bogus results. Hardly anyone tried this but reportedly some Samba users hit the problem in practice. So when we want interfaces compatible we need to fix this. We bite the bullet and define another quota structure used for passing information from/to ->get_dqblk()/->set_dqblk. It's somewhat sad we have to have more conversion routines in fs/quota/quota.c and another copying of quota structure slows down getting of quota information by about 2% but it seems cleaner than overloading e.g. units of d_bcount to bytes. CC: stable@vger.kernel.org Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Родитель
b07ef35244
Коммит
14bf61ffe6
|
@ -667,7 +667,7 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
|
||||||
|
|
||||||
static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
|
static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
|
||||||
s64 change, struct gfs2_quota_data *qd,
|
s64 change, struct gfs2_quota_data *qd,
|
||||||
struct fs_disk_quota *fdq)
|
struct qc_dqblk *fdq)
|
||||||
{
|
{
|
||||||
struct inode *inode = &ip->i_inode;
|
struct inode *inode = &ip->i_inode;
|
||||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||||
|
@ -697,16 +697,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
|
||||||
be64_add_cpu(&q.qu_value, change);
|
be64_add_cpu(&q.qu_value, change);
|
||||||
qd->qd_qb.qb_value = q.qu_value;
|
qd->qd_qb.qb_value = q.qu_value;
|
||||||
if (fdq) {
|
if (fdq) {
|
||||||
if (fdq->d_fieldmask & FS_DQ_BSOFT) {
|
if (fdq->d_fieldmask & QC_SPC_SOFT) {
|
||||||
q.qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift);
|
q.qu_warn = cpu_to_be64(fdq->d_spc_softlimit >> sdp->sd_sb.sb_bsize_shift);
|
||||||
qd->qd_qb.qb_warn = q.qu_warn;
|
qd->qd_qb.qb_warn = q.qu_warn;
|
||||||
}
|
}
|
||||||
if (fdq->d_fieldmask & FS_DQ_BHARD) {
|
if (fdq->d_fieldmask & QC_SPC_HARD) {
|
||||||
q.qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift);
|
q.qu_limit = cpu_to_be64(fdq->d_spc_hardlimit >> sdp->sd_sb.sb_bsize_shift);
|
||||||
qd->qd_qb.qb_limit = q.qu_limit;
|
qd->qd_qb.qb_limit = q.qu_limit;
|
||||||
}
|
}
|
||||||
if (fdq->d_fieldmask & FS_DQ_BCOUNT) {
|
if (fdq->d_fieldmask & QC_SPACE) {
|
||||||
q.qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift);
|
q.qu_value = cpu_to_be64(fdq->d_space >> sdp->sd_sb.sb_bsize_shift);
|
||||||
qd->qd_qb.qb_value = q.qu_value;
|
qd->qd_qb.qb_value = q.qu_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1497,7 +1497,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
|
static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
struct fs_disk_quota *fdq)
|
struct qc_dqblk *fdq)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = sb->s_fs_info;
|
struct gfs2_sbd *sdp = sb->s_fs_info;
|
||||||
struct gfs2_quota_lvb *qlvb;
|
struct gfs2_quota_lvb *qlvb;
|
||||||
|
@ -1505,7 +1505,7 @@ static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
struct gfs2_holder q_gh;
|
struct gfs2_holder q_gh;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
memset(fdq, 0, sizeof(struct fs_disk_quota));
|
memset(fdq, 0, sizeof(*fdq));
|
||||||
|
|
||||||
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
|
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
|
||||||
return -ESRCH; /* Crazy XFS error code */
|
return -ESRCH; /* Crazy XFS error code */
|
||||||
|
@ -1522,12 +1522,9 @@ static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;
|
qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;
|
||||||
fdq->d_version = FS_DQUOT_VERSION;
|
fdq->d_spc_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_sb.sb_bsize_shift;
|
||||||
fdq->d_flags = (qid.type == USRQUOTA) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
|
fdq->d_spc_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_sb.sb_bsize_shift;
|
||||||
fdq->d_id = from_kqid_munged(current_user_ns(), qid);
|
fdq->d_space = be64_to_cpu(qlvb->qb_value) << sdp->sd_sb.sb_bsize_shift;
|
||||||
fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
|
|
||||||
fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
|
|
||||||
fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
|
|
||||||
|
|
||||||
gfs2_glock_dq_uninit(&q_gh);
|
gfs2_glock_dq_uninit(&q_gh);
|
||||||
out:
|
out:
|
||||||
|
@ -1536,10 +1533,10 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GFS2 only supports a subset of the XFS fields */
|
/* GFS2 only supports a subset of the XFS fields */
|
||||||
#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
|
#define GFS2_FIELDMASK (QC_SPC_SOFT|QC_SPC_HARD|QC_SPACE)
|
||||||
|
|
||||||
static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
|
static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
struct fs_disk_quota *fdq)
|
struct qc_dqblk *fdq)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = sb->s_fs_info;
|
struct gfs2_sbd *sdp = sb->s_fs_info;
|
||||||
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
|
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
|
||||||
|
@ -1583,17 +1580,17 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
goto out_i;
|
goto out_i;
|
||||||
|
|
||||||
/* If nothing has changed, this is a no-op */
|
/* If nothing has changed, this is a no-op */
|
||||||
if ((fdq->d_fieldmask & FS_DQ_BSOFT) &&
|
if ((fdq->d_fieldmask & QC_SPC_SOFT) &&
|
||||||
((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
|
((fdq->d_spc_softlimit >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
|
||||||
fdq->d_fieldmask ^= FS_DQ_BSOFT;
|
fdq->d_fieldmask ^= QC_SPC_SOFT;
|
||||||
|
|
||||||
if ((fdq->d_fieldmask & FS_DQ_BHARD) &&
|
if ((fdq->d_fieldmask & QC_SPC_HARD) &&
|
||||||
((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
|
((fdq->d_spc_hardlimit >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
|
||||||
fdq->d_fieldmask ^= FS_DQ_BHARD;
|
fdq->d_fieldmask ^= QC_SPC_HARD;
|
||||||
|
|
||||||
if ((fdq->d_fieldmask & FS_DQ_BCOUNT) &&
|
if ((fdq->d_fieldmask & QC_SPACE) &&
|
||||||
((fdq->d_bcount >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_value)))
|
((fdq->d_space >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_value)))
|
||||||
fdq->d_fieldmask ^= FS_DQ_BCOUNT;
|
fdq->d_fieldmask ^= QC_SPACE;
|
||||||
|
|
||||||
if (fdq->d_fieldmask == 0)
|
if (fdq->d_fieldmask == 0)
|
||||||
goto out_i;
|
goto out_i;
|
||||||
|
|
|
@ -2396,30 +2396,25 @@ static inline qsize_t stoqb(qsize_t space)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generic routine for getting common part of quota structure */
|
/* Generic routine for getting common part of quota structure */
|
||||||
static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
|
static void do_get_dqblk(struct dquot *dquot, struct qc_dqblk *di)
|
||||||
{
|
{
|
||||||
struct mem_dqblk *dm = &dquot->dq_dqb;
|
struct mem_dqblk *dm = &dquot->dq_dqb;
|
||||||
|
|
||||||
memset(di, 0, sizeof(*di));
|
memset(di, 0, sizeof(*di));
|
||||||
di->d_version = FS_DQUOT_VERSION;
|
|
||||||
di->d_flags = dquot->dq_id.type == USRQUOTA ?
|
|
||||||
FS_USER_QUOTA : FS_GROUP_QUOTA;
|
|
||||||
di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
|
|
||||||
|
|
||||||
spin_lock(&dq_data_lock);
|
spin_lock(&dq_data_lock);
|
||||||
di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
|
di->d_spc_hardlimit = dm->dqb_bhardlimit;
|
||||||
di->d_blk_softlimit = stoqb(dm->dqb_bsoftlimit);
|
di->d_spc_softlimit = dm->dqb_bsoftlimit;
|
||||||
di->d_ino_hardlimit = dm->dqb_ihardlimit;
|
di->d_ino_hardlimit = dm->dqb_ihardlimit;
|
||||||
di->d_ino_softlimit = dm->dqb_isoftlimit;
|
di->d_ino_softlimit = dm->dqb_isoftlimit;
|
||||||
di->d_bcount = dm->dqb_curspace + dm->dqb_rsvspace;
|
di->d_space = dm->dqb_curspace + dm->dqb_rsvspace;
|
||||||
di->d_icount = dm->dqb_curinodes;
|
di->d_ino_count = dm->dqb_curinodes;
|
||||||
di->d_btimer = dm->dqb_btime;
|
di->d_spc_timer = dm->dqb_btime;
|
||||||
di->d_itimer = dm->dqb_itime;
|
di->d_ino_timer = dm->dqb_itime;
|
||||||
spin_unlock(&dq_data_lock);
|
spin_unlock(&dq_data_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
|
int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
struct fs_disk_quota *di)
|
struct qc_dqblk *di)
|
||||||
{
|
{
|
||||||
struct dquot *dquot;
|
struct dquot *dquot;
|
||||||
|
|
||||||
|
@ -2433,70 +2428,70 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dquot_get_dqblk);
|
EXPORT_SYMBOL(dquot_get_dqblk);
|
||||||
|
|
||||||
#define VFS_FS_DQ_MASK \
|
#define VFS_QC_MASK \
|
||||||
(FS_DQ_BCOUNT | FS_DQ_BSOFT | FS_DQ_BHARD | \
|
(QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \
|
||||||
FS_DQ_ICOUNT | FS_DQ_ISOFT | FS_DQ_IHARD | \
|
QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \
|
||||||
FS_DQ_BTIMER | FS_DQ_ITIMER)
|
QC_SPC_TIMER | QC_INO_TIMER)
|
||||||
|
|
||||||
/* Generic routine for setting common part of quota structure */
|
/* Generic routine for setting common part of quota structure */
|
||||||
static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
|
static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
|
||||||
{
|
{
|
||||||
struct mem_dqblk *dm = &dquot->dq_dqb;
|
struct mem_dqblk *dm = &dquot->dq_dqb;
|
||||||
int check_blim = 0, check_ilim = 0;
|
int check_blim = 0, check_ilim = 0;
|
||||||
struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
|
struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
|
||||||
|
|
||||||
if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
|
if (di->d_fieldmask & ~VFS_QC_MASK)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (((di->d_fieldmask & FS_DQ_BSOFT) &&
|
if (((di->d_fieldmask & QC_SPC_SOFT) &&
|
||||||
(di->d_blk_softlimit > dqi->dqi_maxblimit)) ||
|
stoqb(di->d_spc_softlimit) > dqi->dqi_maxblimit) ||
|
||||||
((di->d_fieldmask & FS_DQ_BHARD) &&
|
((di->d_fieldmask & QC_SPC_HARD) &&
|
||||||
(di->d_blk_hardlimit > dqi->dqi_maxblimit)) ||
|
stoqb(di->d_spc_hardlimit) > dqi->dqi_maxblimit) ||
|
||||||
((di->d_fieldmask & FS_DQ_ISOFT) &&
|
((di->d_fieldmask & QC_INO_SOFT) &&
|
||||||
(di->d_ino_softlimit > dqi->dqi_maxilimit)) ||
|
(di->d_ino_softlimit > dqi->dqi_maxilimit)) ||
|
||||||
((di->d_fieldmask & FS_DQ_IHARD) &&
|
((di->d_fieldmask & QC_INO_HARD) &&
|
||||||
(di->d_ino_hardlimit > dqi->dqi_maxilimit)))
|
(di->d_ino_hardlimit > dqi->dqi_maxilimit)))
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
spin_lock(&dq_data_lock);
|
spin_lock(&dq_data_lock);
|
||||||
if (di->d_fieldmask & FS_DQ_BCOUNT) {
|
if (di->d_fieldmask & QC_SPACE) {
|
||||||
dm->dqb_curspace = di->d_bcount - dm->dqb_rsvspace;
|
dm->dqb_curspace = di->d_space - dm->dqb_rsvspace;
|
||||||
check_blim = 1;
|
check_blim = 1;
|
||||||
set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
|
set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di->d_fieldmask & FS_DQ_BSOFT)
|
if (di->d_fieldmask & QC_SPC_SOFT)
|
||||||
dm->dqb_bsoftlimit = qbtos(di->d_blk_softlimit);
|
dm->dqb_bsoftlimit = di->d_spc_softlimit;
|
||||||
if (di->d_fieldmask & FS_DQ_BHARD)
|
if (di->d_fieldmask & QC_SPC_HARD)
|
||||||
dm->dqb_bhardlimit = qbtos(di->d_blk_hardlimit);
|
dm->dqb_bhardlimit = di->d_spc_hardlimit;
|
||||||
if (di->d_fieldmask & (FS_DQ_BSOFT | FS_DQ_BHARD)) {
|
if (di->d_fieldmask & (QC_SPC_SOFT | QC_SPC_HARD)) {
|
||||||
check_blim = 1;
|
check_blim = 1;
|
||||||
set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
|
set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di->d_fieldmask & FS_DQ_ICOUNT) {
|
if (di->d_fieldmask & QC_INO_COUNT) {
|
||||||
dm->dqb_curinodes = di->d_icount;
|
dm->dqb_curinodes = di->d_ino_count;
|
||||||
check_ilim = 1;
|
check_ilim = 1;
|
||||||
set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
|
set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di->d_fieldmask & FS_DQ_ISOFT)
|
if (di->d_fieldmask & QC_INO_SOFT)
|
||||||
dm->dqb_isoftlimit = di->d_ino_softlimit;
|
dm->dqb_isoftlimit = di->d_ino_softlimit;
|
||||||
if (di->d_fieldmask & FS_DQ_IHARD)
|
if (di->d_fieldmask & QC_INO_HARD)
|
||||||
dm->dqb_ihardlimit = di->d_ino_hardlimit;
|
dm->dqb_ihardlimit = di->d_ino_hardlimit;
|
||||||
if (di->d_fieldmask & (FS_DQ_ISOFT | FS_DQ_IHARD)) {
|
if (di->d_fieldmask & (QC_INO_SOFT | QC_INO_HARD)) {
|
||||||
check_ilim = 1;
|
check_ilim = 1;
|
||||||
set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
|
set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di->d_fieldmask & FS_DQ_BTIMER) {
|
if (di->d_fieldmask & QC_SPC_TIMER) {
|
||||||
dm->dqb_btime = di->d_btimer;
|
dm->dqb_btime = di->d_spc_timer;
|
||||||
check_blim = 1;
|
check_blim = 1;
|
||||||
set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
|
set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di->d_fieldmask & FS_DQ_ITIMER) {
|
if (di->d_fieldmask & QC_INO_TIMER) {
|
||||||
dm->dqb_itime = di->d_itimer;
|
dm->dqb_itime = di->d_ino_timer;
|
||||||
check_ilim = 1;
|
check_ilim = 1;
|
||||||
set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
|
set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
|
||||||
}
|
}
|
||||||
|
@ -2506,7 +2501,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
|
||||||
dm->dqb_curspace < dm->dqb_bsoftlimit) {
|
dm->dqb_curspace < dm->dqb_bsoftlimit) {
|
||||||
dm->dqb_btime = 0;
|
dm->dqb_btime = 0;
|
||||||
clear_bit(DQ_BLKS_B, &dquot->dq_flags);
|
clear_bit(DQ_BLKS_B, &dquot->dq_flags);
|
||||||
} else if (!(di->d_fieldmask & FS_DQ_BTIMER))
|
} else if (!(di->d_fieldmask & QC_SPC_TIMER))
|
||||||
/* Set grace only if user hasn't provided his own... */
|
/* Set grace only if user hasn't provided his own... */
|
||||||
dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
|
dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
|
||||||
}
|
}
|
||||||
|
@ -2515,7 +2510,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
|
||||||
dm->dqb_curinodes < dm->dqb_isoftlimit) {
|
dm->dqb_curinodes < dm->dqb_isoftlimit) {
|
||||||
dm->dqb_itime = 0;
|
dm->dqb_itime = 0;
|
||||||
clear_bit(DQ_INODES_B, &dquot->dq_flags);
|
clear_bit(DQ_INODES_B, &dquot->dq_flags);
|
||||||
} else if (!(di->d_fieldmask & FS_DQ_ITIMER))
|
} else if (!(di->d_fieldmask & QC_INO_TIMER))
|
||||||
/* Set grace only if user hasn't provided his own... */
|
/* Set grace only if user hasn't provided his own... */
|
||||||
dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
|
dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
|
||||||
}
|
}
|
||||||
|
@ -2531,7 +2526,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
|
||||||
}
|
}
|
||||||
|
|
||||||
int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
|
int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
|
||||||
struct fs_disk_quota *di)
|
struct qc_dqblk *di)
|
||||||
{
|
{
|
||||||
struct dquot *dquot;
|
struct dquot *dquot;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
162
fs/quota/quota.c
162
fs/quota/quota.c
|
@ -118,17 +118,27 @@ static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
|
||||||
return sb->s_qcop->set_info(sb, type, &info);
|
return sb->s_qcop->set_info(sb, type, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
|
static inline qsize_t qbtos(qsize_t blocks)
|
||||||
|
{
|
||||||
|
return blocks << QIF_DQBLKSIZE_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qsize_t stoqb(qsize_t space)
|
||||||
|
{
|
||||||
|
return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src)
|
||||||
{
|
{
|
||||||
memset(dst, 0, sizeof(*dst));
|
memset(dst, 0, sizeof(*dst));
|
||||||
dst->dqb_bhardlimit = src->d_blk_hardlimit;
|
dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
|
||||||
dst->dqb_bsoftlimit = src->d_blk_softlimit;
|
dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
|
||||||
dst->dqb_curspace = src->d_bcount;
|
dst->dqb_curspace = src->d_space;
|
||||||
dst->dqb_ihardlimit = src->d_ino_hardlimit;
|
dst->dqb_ihardlimit = src->d_ino_hardlimit;
|
||||||
dst->dqb_isoftlimit = src->d_ino_softlimit;
|
dst->dqb_isoftlimit = src->d_ino_softlimit;
|
||||||
dst->dqb_curinodes = src->d_icount;
|
dst->dqb_curinodes = src->d_ino_count;
|
||||||
dst->dqb_btime = src->d_btimer;
|
dst->dqb_btime = src->d_spc_timer;
|
||||||
dst->dqb_itime = src->d_itimer;
|
dst->dqb_itime = src->d_ino_timer;
|
||||||
dst->dqb_valid = QIF_ALL;
|
dst->dqb_valid = QIF_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +146,7 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
|
||||||
void __user *addr)
|
void __user *addr)
|
||||||
{
|
{
|
||||||
struct kqid qid;
|
struct kqid qid;
|
||||||
struct fs_disk_quota fdq;
|
struct qc_dqblk fdq;
|
||||||
struct if_dqblk idq;
|
struct if_dqblk idq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -154,36 +164,36 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
|
static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
|
||||||
{
|
{
|
||||||
dst->d_blk_hardlimit = src->dqb_bhardlimit;
|
dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
|
||||||
dst->d_blk_softlimit = src->dqb_bsoftlimit;
|
dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
|
||||||
dst->d_bcount = src->dqb_curspace;
|
dst->d_space = src->dqb_curspace;
|
||||||
dst->d_ino_hardlimit = src->dqb_ihardlimit;
|
dst->d_ino_hardlimit = src->dqb_ihardlimit;
|
||||||
dst->d_ino_softlimit = src->dqb_isoftlimit;
|
dst->d_ino_softlimit = src->dqb_isoftlimit;
|
||||||
dst->d_icount = src->dqb_curinodes;
|
dst->d_ino_count = src->dqb_curinodes;
|
||||||
dst->d_btimer = src->dqb_btime;
|
dst->d_spc_timer = src->dqb_btime;
|
||||||
dst->d_itimer = src->dqb_itime;
|
dst->d_ino_timer = src->dqb_itime;
|
||||||
|
|
||||||
dst->d_fieldmask = 0;
|
dst->d_fieldmask = 0;
|
||||||
if (src->dqb_valid & QIF_BLIMITS)
|
if (src->dqb_valid & QIF_BLIMITS)
|
||||||
dst->d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
|
dst->d_fieldmask |= QC_SPC_SOFT | QC_SPC_HARD;
|
||||||
if (src->dqb_valid & QIF_SPACE)
|
if (src->dqb_valid & QIF_SPACE)
|
||||||
dst->d_fieldmask |= FS_DQ_BCOUNT;
|
dst->d_fieldmask |= QC_SPACE;
|
||||||
if (src->dqb_valid & QIF_ILIMITS)
|
if (src->dqb_valid & QIF_ILIMITS)
|
||||||
dst->d_fieldmask |= FS_DQ_ISOFT | FS_DQ_IHARD;
|
dst->d_fieldmask |= QC_INO_SOFT | QC_INO_HARD;
|
||||||
if (src->dqb_valid & QIF_INODES)
|
if (src->dqb_valid & QIF_INODES)
|
||||||
dst->d_fieldmask |= FS_DQ_ICOUNT;
|
dst->d_fieldmask |= QC_INO_COUNT;
|
||||||
if (src->dqb_valid & QIF_BTIME)
|
if (src->dqb_valid & QIF_BTIME)
|
||||||
dst->d_fieldmask |= FS_DQ_BTIMER;
|
dst->d_fieldmask |= QC_SPC_TIMER;
|
||||||
if (src->dqb_valid & QIF_ITIME)
|
if (src->dqb_valid & QIF_ITIME)
|
||||||
dst->d_fieldmask |= FS_DQ_ITIMER;
|
dst->d_fieldmask |= QC_INO_TIMER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quota_setquota(struct super_block *sb, int type, qid_t id,
|
static int quota_setquota(struct super_block *sb, int type, qid_t id,
|
||||||
void __user *addr)
|
void __user *addr)
|
||||||
{
|
{
|
||||||
struct fs_disk_quota fdq;
|
struct qc_dqblk fdq;
|
||||||
struct if_dqblk idq;
|
struct if_dqblk idq;
|
||||||
struct kqid qid;
|
struct kqid qid;
|
||||||
|
|
||||||
|
@ -247,10 +257,78 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XFS defines BBTOB and BTOBB macros inside fs/xfs/ and we cannot move them
|
||||||
|
* out of there as xfsprogs rely on definitions being in that header file. So
|
||||||
|
* just define same functions here for quota purposes.
|
||||||
|
*/
|
||||||
|
#define XFS_BB_SHIFT 9
|
||||||
|
|
||||||
|
static inline u64 quota_bbtob(u64 blocks)
|
||||||
|
{
|
||||||
|
return blocks << XFS_BB_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 quota_btobb(u64 bytes)
|
||||||
|
{
|
||||||
|
return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
|
||||||
|
{
|
||||||
|
dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
|
||||||
|
dst->d_spc_softlimit = quota_bbtob(src->d_blk_softlimit);
|
||||||
|
dst->d_ino_hardlimit = src->d_ino_hardlimit;
|
||||||
|
dst->d_ino_softlimit = src->d_ino_softlimit;
|
||||||
|
dst->d_space = quota_bbtob(src->d_bcount);
|
||||||
|
dst->d_ino_count = src->d_icount;
|
||||||
|
dst->d_ino_timer = src->d_itimer;
|
||||||
|
dst->d_spc_timer = src->d_btimer;
|
||||||
|
dst->d_ino_warns = src->d_iwarns;
|
||||||
|
dst->d_spc_warns = src->d_bwarns;
|
||||||
|
dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
|
||||||
|
dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
|
||||||
|
dst->d_rt_space = quota_bbtob(src->d_rtbcount);
|
||||||
|
dst->d_rt_spc_timer = src->d_rtbtimer;
|
||||||
|
dst->d_rt_spc_warns = src->d_rtbwarns;
|
||||||
|
dst->d_fieldmask = 0;
|
||||||
|
if (src->d_fieldmask & FS_DQ_ISOFT)
|
||||||
|
dst->d_fieldmask |= QC_INO_SOFT;
|
||||||
|
if (src->d_fieldmask & FS_DQ_IHARD)
|
||||||
|
dst->d_fieldmask |= QC_INO_HARD;
|
||||||
|
if (src->d_fieldmask & FS_DQ_BSOFT)
|
||||||
|
dst->d_fieldmask |= QC_SPC_SOFT;
|
||||||
|
if (src->d_fieldmask & FS_DQ_BHARD)
|
||||||
|
dst->d_fieldmask |= QC_SPC_HARD;
|
||||||
|
if (src->d_fieldmask & FS_DQ_RTBSOFT)
|
||||||
|
dst->d_fieldmask |= QC_RT_SPC_SOFT;
|
||||||
|
if (src->d_fieldmask & FS_DQ_RTBHARD)
|
||||||
|
dst->d_fieldmask |= QC_RT_SPC_HARD;
|
||||||
|
if (src->d_fieldmask & FS_DQ_BTIMER)
|
||||||
|
dst->d_fieldmask |= QC_SPC_TIMER;
|
||||||
|
if (src->d_fieldmask & FS_DQ_ITIMER)
|
||||||
|
dst->d_fieldmask |= QC_INO_TIMER;
|
||||||
|
if (src->d_fieldmask & FS_DQ_RTBTIMER)
|
||||||
|
dst->d_fieldmask |= QC_RT_SPC_TIMER;
|
||||||
|
if (src->d_fieldmask & FS_DQ_BWARNS)
|
||||||
|
dst->d_fieldmask |= QC_SPC_WARNS;
|
||||||
|
if (src->d_fieldmask & FS_DQ_IWARNS)
|
||||||
|
dst->d_fieldmask |= QC_INO_WARNS;
|
||||||
|
if (src->d_fieldmask & FS_DQ_RTBWARNS)
|
||||||
|
dst->d_fieldmask |= QC_RT_SPC_WARNS;
|
||||||
|
if (src->d_fieldmask & FS_DQ_BCOUNT)
|
||||||
|
dst->d_fieldmask |= QC_SPACE;
|
||||||
|
if (src->d_fieldmask & FS_DQ_ICOUNT)
|
||||||
|
dst->d_fieldmask |= QC_INO_COUNT;
|
||||||
|
if (src->d_fieldmask & FS_DQ_RTBCOUNT)
|
||||||
|
dst->d_fieldmask |= QC_RT_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
||||||
void __user *addr)
|
void __user *addr)
|
||||||
{
|
{
|
||||||
struct fs_disk_quota fdq;
|
struct fs_disk_quota fdq;
|
||||||
|
struct qc_dqblk qdq;
|
||||||
struct kqid qid;
|
struct kqid qid;
|
||||||
|
|
||||||
if (copy_from_user(&fdq, addr, sizeof(fdq)))
|
if (copy_from_user(&fdq, addr, sizeof(fdq)))
|
||||||
|
@ -260,13 +338,44 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
||||||
qid = make_kqid(current_user_ns(), type, id);
|
qid = make_kqid(current_user_ns(), type, id);
|
||||||
if (!qid_valid(qid))
|
if (!qid_valid(qid))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return sb->s_qcop->set_dqblk(sb, qid, &fdq);
|
copy_from_xfs_dqblk(&qdq, &fdq);
|
||||||
|
return sb->s_qcop->set_dqblk(sb, qid, &qdq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
|
||||||
|
int type, qid_t id)
|
||||||
|
{
|
||||||
|
memset(dst, 0, sizeof(*dst));
|
||||||
|
dst->d_version = FS_DQUOT_VERSION;
|
||||||
|
dst->d_id = id;
|
||||||
|
if (type == USRQUOTA)
|
||||||
|
dst->d_flags = FS_USER_QUOTA;
|
||||||
|
else if (type == PRJQUOTA)
|
||||||
|
dst->d_flags = FS_PROJ_QUOTA;
|
||||||
|
else
|
||||||
|
dst->d_flags = FS_GROUP_QUOTA;
|
||||||
|
dst->d_blk_hardlimit = quota_btobb(src->d_spc_hardlimit);
|
||||||
|
dst->d_blk_softlimit = quota_btobb(src->d_spc_softlimit);
|
||||||
|
dst->d_ino_hardlimit = src->d_ino_hardlimit;
|
||||||
|
dst->d_ino_softlimit = src->d_ino_softlimit;
|
||||||
|
dst->d_bcount = quota_btobb(src->d_space);
|
||||||
|
dst->d_icount = src->d_ino_count;
|
||||||
|
dst->d_itimer = src->d_ino_timer;
|
||||||
|
dst->d_btimer = src->d_spc_timer;
|
||||||
|
dst->d_iwarns = src->d_ino_warns;
|
||||||
|
dst->d_bwarns = src->d_spc_warns;
|
||||||
|
dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
|
||||||
|
dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
|
||||||
|
dst->d_rtbcount = quota_btobb(src->d_rt_space);
|
||||||
|
dst->d_rtbtimer = src->d_rt_spc_timer;
|
||||||
|
dst->d_rtbwarns = src->d_rt_spc_warns;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quota_getxquota(struct super_block *sb, int type, qid_t id,
|
static int quota_getxquota(struct super_block *sb, int type, qid_t id,
|
||||||
void __user *addr)
|
void __user *addr)
|
||||||
{
|
{
|
||||||
struct fs_disk_quota fdq;
|
struct fs_disk_quota fdq;
|
||||||
|
struct qc_dqblk qdq;
|
||||||
struct kqid qid;
|
struct kqid qid;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -275,8 +384,11 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
|
||||||
qid = make_kqid(current_user_ns(), type, id);
|
qid = make_kqid(current_user_ns(), type, id);
|
||||||
if (!qid_valid(qid))
|
if (!qid_valid(qid))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
|
ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
|
||||||
if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
copy_to_xfs_dqblk(&fdq, &qdq, type, id);
|
||||||
|
if (copy_to_user(addr, &fdq, sizeof(fdq)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,9 +166,9 @@ extern void xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
|
||||||
/* quota ops */
|
/* quota ops */
|
||||||
extern int xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
|
extern int xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
|
||||||
extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
|
extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
|
||||||
uint, struct fs_disk_quota *);
|
uint, struct qc_dqblk *);
|
||||||
extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
|
extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
|
||||||
struct fs_disk_quota *);
|
struct qc_dqblk *);
|
||||||
extern int xfs_qm_scall_getqstat(struct xfs_mount *,
|
extern int xfs_qm_scall_getqstat(struct xfs_mount *,
|
||||||
struct fs_quota_stat *);
|
struct fs_quota_stat *);
|
||||||
extern int xfs_qm_scall_getqstatv(struct xfs_mount *,
|
extern int xfs_qm_scall_getqstatv(struct xfs_mount *,
|
||||||
|
|
|
@ -39,7 +39,6 @@ STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
|
||||||
STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
|
STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
|
||||||
uint);
|
uint);
|
||||||
STATIC uint xfs_qm_export_flags(uint);
|
STATIC uint xfs_qm_export_flags(uint);
|
||||||
STATIC uint xfs_qm_export_qtype_flags(uint);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn off quota accounting and/or enforcement for all udquots and/or
|
* Turn off quota accounting and/or enforcement for all udquots and/or
|
||||||
|
@ -573,8 +572,8 @@ xfs_qm_scall_getqstatv(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define XFS_DQ_MASK \
|
#define XFS_QC_MASK \
|
||||||
(FS_DQ_LIMIT_MASK | FS_DQ_TIMER_MASK | FS_DQ_WARNS_MASK)
|
(QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust quota limits, and start/stop timers accordingly.
|
* Adjust quota limits, and start/stop timers accordingly.
|
||||||
|
@ -584,7 +583,7 @@ xfs_qm_scall_setqlim(
|
||||||
struct xfs_mount *mp,
|
struct xfs_mount *mp,
|
||||||
xfs_dqid_t id,
|
xfs_dqid_t id,
|
||||||
uint type,
|
uint type,
|
||||||
fs_disk_quota_t *newlim)
|
struct qc_dqblk *newlim)
|
||||||
{
|
{
|
||||||
struct xfs_quotainfo *q = mp->m_quotainfo;
|
struct xfs_quotainfo *q = mp->m_quotainfo;
|
||||||
struct xfs_disk_dquot *ddq;
|
struct xfs_disk_dquot *ddq;
|
||||||
|
@ -593,9 +592,9 @@ xfs_qm_scall_setqlim(
|
||||||
int error;
|
int error;
|
||||||
xfs_qcnt_t hard, soft;
|
xfs_qcnt_t hard, soft;
|
||||||
|
|
||||||
if (newlim->d_fieldmask & ~XFS_DQ_MASK)
|
if (newlim->d_fieldmask & ~XFS_QC_MASK)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)
|
if ((newlim->d_fieldmask & XFS_QC_MASK) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -633,11 +632,11 @@ xfs_qm_scall_setqlim(
|
||||||
/*
|
/*
|
||||||
* Make sure that hardlimits are >= soft limits before changing.
|
* Make sure that hardlimits are >= soft limits before changing.
|
||||||
*/
|
*/
|
||||||
hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
|
hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
|
||||||
(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
|
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
|
||||||
be64_to_cpu(ddq->d_blk_hardlimit);
|
be64_to_cpu(ddq->d_blk_hardlimit);
|
||||||
soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
|
soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
|
||||||
(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
|
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
|
||||||
be64_to_cpu(ddq->d_blk_softlimit);
|
be64_to_cpu(ddq->d_blk_softlimit);
|
||||||
if (hard == 0 || hard >= soft) {
|
if (hard == 0 || hard >= soft) {
|
||||||
ddq->d_blk_hardlimit = cpu_to_be64(hard);
|
ddq->d_blk_hardlimit = cpu_to_be64(hard);
|
||||||
|
@ -650,11 +649,11 @@ xfs_qm_scall_setqlim(
|
||||||
} else {
|
} else {
|
||||||
xfs_debug(mp, "blkhard %Ld < blksoft %Ld", hard, soft);
|
xfs_debug(mp, "blkhard %Ld < blksoft %Ld", hard, soft);
|
||||||
}
|
}
|
||||||
hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
|
hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
|
||||||
(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
|
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
|
||||||
be64_to_cpu(ddq->d_rtb_hardlimit);
|
be64_to_cpu(ddq->d_rtb_hardlimit);
|
||||||
soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
|
soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
|
||||||
(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
|
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
|
||||||
be64_to_cpu(ddq->d_rtb_softlimit);
|
be64_to_cpu(ddq->d_rtb_softlimit);
|
||||||
if (hard == 0 || hard >= soft) {
|
if (hard == 0 || hard >= soft) {
|
||||||
ddq->d_rtb_hardlimit = cpu_to_be64(hard);
|
ddq->d_rtb_hardlimit = cpu_to_be64(hard);
|
||||||
|
@ -667,10 +666,10 @@ xfs_qm_scall_setqlim(
|
||||||
xfs_debug(mp, "rtbhard %Ld < rtbsoft %Ld", hard, soft);
|
xfs_debug(mp, "rtbhard %Ld < rtbsoft %Ld", hard, soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
|
hard = (newlim->d_fieldmask & QC_INO_HARD) ?
|
||||||
(xfs_qcnt_t) newlim->d_ino_hardlimit :
|
(xfs_qcnt_t) newlim->d_ino_hardlimit :
|
||||||
be64_to_cpu(ddq->d_ino_hardlimit);
|
be64_to_cpu(ddq->d_ino_hardlimit);
|
||||||
soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
|
soft = (newlim->d_fieldmask & QC_INO_SOFT) ?
|
||||||
(xfs_qcnt_t) newlim->d_ino_softlimit :
|
(xfs_qcnt_t) newlim->d_ino_softlimit :
|
||||||
be64_to_cpu(ddq->d_ino_softlimit);
|
be64_to_cpu(ddq->d_ino_softlimit);
|
||||||
if (hard == 0 || hard >= soft) {
|
if (hard == 0 || hard >= soft) {
|
||||||
|
@ -687,12 +686,12 @@ xfs_qm_scall_setqlim(
|
||||||
/*
|
/*
|
||||||
* Update warnings counter(s) if requested
|
* Update warnings counter(s) if requested
|
||||||
*/
|
*/
|
||||||
if (newlim->d_fieldmask & FS_DQ_BWARNS)
|
if (newlim->d_fieldmask & QC_SPC_WARNS)
|
||||||
ddq->d_bwarns = cpu_to_be16(newlim->d_bwarns);
|
ddq->d_bwarns = cpu_to_be16(newlim->d_spc_warns);
|
||||||
if (newlim->d_fieldmask & FS_DQ_IWARNS)
|
if (newlim->d_fieldmask & QC_INO_WARNS)
|
||||||
ddq->d_iwarns = cpu_to_be16(newlim->d_iwarns);
|
ddq->d_iwarns = cpu_to_be16(newlim->d_ino_warns);
|
||||||
if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
|
if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
|
||||||
ddq->d_rtbwarns = cpu_to_be16(newlim->d_rtbwarns);
|
ddq->d_rtbwarns = cpu_to_be16(newlim->d_rt_spc_warns);
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
/*
|
/*
|
||||||
|
@ -702,24 +701,24 @@ xfs_qm_scall_setqlim(
|
||||||
* soft and hard limit values (already done, above), and
|
* soft and hard limit values (already done, above), and
|
||||||
* for warnings.
|
* for warnings.
|
||||||
*/
|
*/
|
||||||
if (newlim->d_fieldmask & FS_DQ_BTIMER) {
|
if (newlim->d_fieldmask & QC_SPC_TIMER) {
|
||||||
q->qi_btimelimit = newlim->d_btimer;
|
q->qi_btimelimit = newlim->d_spc_timer;
|
||||||
ddq->d_btimer = cpu_to_be32(newlim->d_btimer);
|
ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
|
||||||
}
|
}
|
||||||
if (newlim->d_fieldmask & FS_DQ_ITIMER) {
|
if (newlim->d_fieldmask & QC_INO_TIMER) {
|
||||||
q->qi_itimelimit = newlim->d_itimer;
|
q->qi_itimelimit = newlim->d_ino_timer;
|
||||||
ddq->d_itimer = cpu_to_be32(newlim->d_itimer);
|
ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
|
||||||
}
|
}
|
||||||
if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
|
if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
|
||||||
q->qi_rtbtimelimit = newlim->d_rtbtimer;
|
q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
|
||||||
ddq->d_rtbtimer = cpu_to_be32(newlim->d_rtbtimer);
|
ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
|
||||||
}
|
}
|
||||||
if (newlim->d_fieldmask & FS_DQ_BWARNS)
|
if (newlim->d_fieldmask & QC_SPC_WARNS)
|
||||||
q->qi_bwarnlimit = newlim->d_bwarns;
|
q->qi_bwarnlimit = newlim->d_spc_warns;
|
||||||
if (newlim->d_fieldmask & FS_DQ_IWARNS)
|
if (newlim->d_fieldmask & QC_INO_WARNS)
|
||||||
q->qi_iwarnlimit = newlim->d_iwarns;
|
q->qi_iwarnlimit = newlim->d_ino_warns;
|
||||||
if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
|
if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
|
||||||
q->qi_rtbwarnlimit = newlim->d_rtbwarns;
|
q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If the user is now over quota, start the timelimit.
|
* If the user is now over quota, start the timelimit.
|
||||||
|
@ -824,7 +823,7 @@ xfs_qm_scall_getquota(
|
||||||
struct xfs_mount *mp,
|
struct xfs_mount *mp,
|
||||||
xfs_dqid_t id,
|
xfs_dqid_t id,
|
||||||
uint type,
|
uint type,
|
||||||
struct fs_disk_quota *dst)
|
struct qc_dqblk *dst)
|
||||||
{
|
{
|
||||||
struct xfs_dquot *dqp;
|
struct xfs_dquot *dqp;
|
||||||
int error;
|
int error;
|
||||||
|
@ -848,28 +847,25 @@ xfs_qm_scall_getquota(
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(dst, 0, sizeof(*dst));
|
memset(dst, 0, sizeof(*dst));
|
||||||
dst->d_version = FS_DQUOT_VERSION;
|
dst->d_spc_hardlimit =
|
||||||
dst->d_flags = xfs_qm_export_qtype_flags(dqp->q_core.d_flags);
|
XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
|
||||||
dst->d_id = be32_to_cpu(dqp->q_core.d_id);
|
dst->d_spc_softlimit =
|
||||||
dst->d_blk_hardlimit =
|
XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_softlimit));
|
||||||
XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
|
|
||||||
dst->d_blk_softlimit =
|
|
||||||
XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_softlimit));
|
|
||||||
dst->d_ino_hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
|
dst->d_ino_hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
|
||||||
dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
|
dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
|
||||||
dst->d_bcount = XFS_FSB_TO_BB(mp, dqp->q_res_bcount);
|
dst->d_space = XFS_FSB_TO_B(mp, dqp->q_res_bcount);
|
||||||
dst->d_icount = dqp->q_res_icount;
|
dst->d_ino_count = dqp->q_res_icount;
|
||||||
dst->d_btimer = be32_to_cpu(dqp->q_core.d_btimer);
|
dst->d_spc_timer = be32_to_cpu(dqp->q_core.d_btimer);
|
||||||
dst->d_itimer = be32_to_cpu(dqp->q_core.d_itimer);
|
dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer);
|
||||||
dst->d_iwarns = be16_to_cpu(dqp->q_core.d_iwarns);
|
dst->d_ino_warns = be16_to_cpu(dqp->q_core.d_iwarns);
|
||||||
dst->d_bwarns = be16_to_cpu(dqp->q_core.d_bwarns);
|
dst->d_spc_warns = be16_to_cpu(dqp->q_core.d_bwarns);
|
||||||
dst->d_rtb_hardlimit =
|
dst->d_rt_spc_hardlimit =
|
||||||
XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
|
XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
|
||||||
dst->d_rtb_softlimit =
|
dst->d_rt_spc_softlimit =
|
||||||
XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
|
XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
|
||||||
dst->d_rtbcount = XFS_FSB_TO_BB(mp, dqp->q_res_rtbcount);
|
dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_res_rtbcount);
|
||||||
dst->d_rtbtimer = be32_to_cpu(dqp->q_core.d_rtbtimer);
|
dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
|
||||||
dst->d_rtbwarns = be16_to_cpu(dqp->q_core.d_rtbwarns);
|
dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internally, we don't reset all the timers when quota enforcement
|
* Internally, we don't reset all the timers when quota enforcement
|
||||||
|
@ -882,23 +878,23 @@ xfs_qm_scall_getquota(
|
||||||
dqp->q_core.d_flags == XFS_DQ_GROUP) ||
|
dqp->q_core.d_flags == XFS_DQ_GROUP) ||
|
||||||
(!XFS_IS_PQUOTA_ENFORCED(mp) &&
|
(!XFS_IS_PQUOTA_ENFORCED(mp) &&
|
||||||
dqp->q_core.d_flags == XFS_DQ_PROJ)) {
|
dqp->q_core.d_flags == XFS_DQ_PROJ)) {
|
||||||
dst->d_btimer = 0;
|
dst->d_spc_timer = 0;
|
||||||
dst->d_itimer = 0;
|
dst->d_ino_timer = 0;
|
||||||
dst->d_rtbtimer = 0;
|
dst->d_rt_spc_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
|
if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
|
||||||
(XFS_IS_GQUOTA_ENFORCED(mp) && dst->d_flags == FS_GROUP_QUOTA) ||
|
(XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
|
||||||
(XFS_IS_PQUOTA_ENFORCED(mp) && dst->d_flags == FS_PROJ_QUOTA)) &&
|
(XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
|
||||||
dst->d_id != 0) {
|
id != 0) {
|
||||||
if ((dst->d_bcount > dst->d_blk_softlimit) &&
|
if ((dst->d_space > dst->d_spc_softlimit) &&
|
||||||
(dst->d_blk_softlimit > 0)) {
|
(dst->d_spc_softlimit > 0)) {
|
||||||
ASSERT(dst->d_btimer != 0);
|
ASSERT(dst->d_spc_timer != 0);
|
||||||
}
|
}
|
||||||
if ((dst->d_icount > dst->d_ino_softlimit) &&
|
if ((dst->d_ino_count > dst->d_ino_softlimit) &&
|
||||||
(dst->d_ino_softlimit > 0)) {
|
(dst->d_ino_softlimit > 0)) {
|
||||||
ASSERT(dst->d_itimer != 0);
|
ASSERT(dst->d_ino_timer != 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -907,26 +903,6 @@ out_put:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC uint
|
|
||||||
xfs_qm_export_qtype_flags(
|
|
||||||
uint flags)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Can't be more than one, or none.
|
|
||||||
*/
|
|
||||||
ASSERT((flags & (FS_PROJ_QUOTA | FS_USER_QUOTA)) !=
|
|
||||||
(FS_PROJ_QUOTA | FS_USER_QUOTA));
|
|
||||||
ASSERT((flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)) !=
|
|
||||||
(FS_PROJ_QUOTA | FS_GROUP_QUOTA));
|
|
||||||
ASSERT((flags & (FS_USER_QUOTA | FS_GROUP_QUOTA)) !=
|
|
||||||
(FS_USER_QUOTA | FS_GROUP_QUOTA));
|
|
||||||
ASSERT((flags & (FS_PROJ_QUOTA|FS_USER_QUOTA|FS_GROUP_QUOTA)) != 0);
|
|
||||||
|
|
||||||
return (flags & XFS_DQ_USER) ?
|
|
||||||
FS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
|
|
||||||
FS_PROJ_QUOTA : FS_GROUP_QUOTA;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC uint
|
STATIC uint
|
||||||
xfs_qm_export_flags(
|
xfs_qm_export_flags(
|
||||||
uint flags)
|
uint flags)
|
||||||
|
|
|
@ -131,7 +131,7 @@ STATIC int
|
||||||
xfs_fs_get_dqblk(
|
xfs_fs_get_dqblk(
|
||||||
struct super_block *sb,
|
struct super_block *sb,
|
||||||
struct kqid qid,
|
struct kqid qid,
|
||||||
struct fs_disk_quota *fdq)
|
struct qc_dqblk *qdq)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = XFS_M(sb);
|
struct xfs_mount *mp = XFS_M(sb);
|
||||||
|
|
||||||
|
@ -141,14 +141,14 @@ xfs_fs_get_dqblk(
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
|
return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
|
||||||
xfs_quota_type(qid.type), fdq);
|
xfs_quota_type(qid.type), qdq);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_fs_set_dqblk(
|
xfs_fs_set_dqblk(
|
||||||
struct super_block *sb,
|
struct super_block *sb,
|
||||||
struct kqid qid,
|
struct kqid qid,
|
||||||
struct fs_disk_quota *fdq)
|
struct qc_dqblk *qdq)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = XFS_M(sb);
|
struct xfs_mount *mp = XFS_M(sb);
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ xfs_fs_set_dqblk(
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
return xfs_qm_scall_setqlim(mp, from_kqid(&init_user_ns, qid),
|
return xfs_qm_scall_setqlim(mp, from_kqid(&init_user_ns, qid),
|
||||||
xfs_quota_type(qid.type), fdq);
|
xfs_quota_type(qid.type), qdq);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct quotactl_ops xfs_quotactl_operations = {
|
const struct quotactl_ops xfs_quotactl_operations = {
|
||||||
|
|
|
@ -321,6 +321,49 @@ struct dquot_operations {
|
||||||
|
|
||||||
struct path;
|
struct path;
|
||||||
|
|
||||||
|
/* Structure for communicating via ->get_dqblk() & ->set_dqblk() */
|
||||||
|
struct qc_dqblk {
|
||||||
|
int d_fieldmask; /* mask of fields to change in ->set_dqblk() */
|
||||||
|
u64 d_spc_hardlimit; /* absolute limit on used space */
|
||||||
|
u64 d_spc_softlimit; /* preferred limit on used space */
|
||||||
|
u64 d_ino_hardlimit; /* maximum # allocated inodes */
|
||||||
|
u64 d_ino_softlimit; /* preferred inode limit */
|
||||||
|
u64 d_space; /* Space owned by the user */
|
||||||
|
u64 d_ino_count; /* # inodes owned by the user */
|
||||||
|
s64 d_ino_timer; /* zero if within inode limits */
|
||||||
|
/* if not, we refuse service */
|
||||||
|
s64 d_spc_timer; /* similar to above; for space */
|
||||||
|
int d_ino_warns; /* # warnings issued wrt num inodes */
|
||||||
|
int d_spc_warns; /* # warnings issued wrt used space */
|
||||||
|
u64 d_rt_spc_hardlimit; /* absolute limit on realtime space */
|
||||||
|
u64 d_rt_spc_softlimit; /* preferred limit on RT space */
|
||||||
|
u64 d_rt_space; /* realtime space owned */
|
||||||
|
s64 d_rt_spc_timer; /* similar to above; for RT space */
|
||||||
|
int d_rt_spc_warns; /* # warnings issued wrt RT space */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Field specifiers for ->set_dqblk() in struct qc_dqblk */
|
||||||
|
#define QC_INO_SOFT (1<<0)
|
||||||
|
#define QC_INO_HARD (1<<1)
|
||||||
|
#define QC_SPC_SOFT (1<<2)
|
||||||
|
#define QC_SPC_HARD (1<<3)
|
||||||
|
#define QC_RT_SPC_SOFT (1<<4)
|
||||||
|
#define QC_RT_SPC_HARD (1<<5)
|
||||||
|
#define QC_LIMIT_MASK (QC_INO_SOFT | QC_INO_HARD | QC_SPC_SOFT | QC_SPC_HARD | \
|
||||||
|
QC_RT_SPC_SOFT | QC_RT_SPC_HARD)
|
||||||
|
#define QC_SPC_TIMER (1<<6)
|
||||||
|
#define QC_INO_TIMER (1<<7)
|
||||||
|
#define QC_RT_SPC_TIMER (1<<8)
|
||||||
|
#define QC_TIMER_MASK (QC_SPC_TIMER | QC_INO_TIMER | QC_RT_SPC_TIMER)
|
||||||
|
#define QC_SPC_WARNS (1<<9)
|
||||||
|
#define QC_INO_WARNS (1<<10)
|
||||||
|
#define QC_RT_SPC_WARNS (1<<11)
|
||||||
|
#define QC_WARNS_MASK (QC_SPC_WARNS | QC_INO_WARNS | QC_RT_SPC_WARNS)
|
||||||
|
#define QC_SPACE (1<<12)
|
||||||
|
#define QC_INO_COUNT (1<<13)
|
||||||
|
#define QC_RT_SPACE (1<<14)
|
||||||
|
#define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE)
|
||||||
|
|
||||||
/* Operations handling requests from userspace */
|
/* Operations handling requests from userspace */
|
||||||
struct quotactl_ops {
|
struct quotactl_ops {
|
||||||
int (*quota_on)(struct super_block *, int, int, struct path *);
|
int (*quota_on)(struct super_block *, int, int, struct path *);
|
||||||
|
@ -329,8 +372,8 @@ struct quotactl_ops {
|
||||||
int (*quota_sync)(struct super_block *, int);
|
int (*quota_sync)(struct super_block *, int);
|
||||||
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
|
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
|
||||||
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
|
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
|
||||||
int (*get_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
|
int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);
|
||||||
int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
|
int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);
|
||||||
int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
|
int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
|
||||||
int (*set_xstate)(struct super_block *, unsigned int, int);
|
int (*set_xstate)(struct super_block *, unsigned int, int);
|
||||||
int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
|
int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
|
||||||
|
|
|
@ -98,9 +98,9 @@ int dquot_quota_sync(struct super_block *sb, int type);
|
||||||
int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
|
int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
|
||||||
int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
|
int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
|
||||||
int dquot_get_dqblk(struct super_block *sb, struct kqid id,
|
int dquot_get_dqblk(struct super_block *sb, struct kqid id,
|
||||||
struct fs_disk_quota *di);
|
struct qc_dqblk *di);
|
||||||
int dquot_set_dqblk(struct super_block *sb, struct kqid id,
|
int dquot_set_dqblk(struct super_block *sb, struct kqid id,
|
||||||
struct fs_disk_quota *di);
|
struct qc_dqblk *di);
|
||||||
|
|
||||||
int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
|
int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
|
||||||
int dquot_transfer(struct inode *inode, struct iattr *iattr);
|
int dquot_transfer(struct inode *inode, struct iattr *iattr);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче