Merge branch 'for_linus' into for_next
This commit is contained in:
@@ -2396,30 +2396,25 @@ static inline qsize_t stoqb(qsize_t space)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
|
||||
di->d_blk_softlimit = stoqb(dm->dqb_bsoftlimit);
|
||||
di->d_spc_hardlimit = dm->dqb_bhardlimit;
|
||||
di->d_spc_softlimit = dm->dqb_bsoftlimit;
|
||||
di->d_ino_hardlimit = dm->dqb_ihardlimit;
|
||||
di->d_ino_softlimit = dm->dqb_isoftlimit;
|
||||
di->d_bcount = dm->dqb_curspace + dm->dqb_rsvspace;
|
||||
di->d_icount = dm->dqb_curinodes;
|
||||
di->d_btimer = dm->dqb_btime;
|
||||
di->d_itimer = dm->dqb_itime;
|
||||
di->d_space = dm->dqb_curspace + dm->dqb_rsvspace;
|
||||
di->d_ino_count = dm->dqb_curinodes;
|
||||
di->d_spc_timer = dm->dqb_btime;
|
||||
di->d_ino_timer = dm->dqb_itime;
|
||||
spin_unlock(&dq_data_lock);
|
||||
}
|
||||
|
||||
int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||
struct fs_disk_quota *di)
|
||||
struct qc_dqblk *di)
|
||||
{
|
||||
struct dquot *dquot;
|
||||
|
||||
@@ -2433,70 +2428,70 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
|
||||
}
|
||||
EXPORT_SYMBOL(dquot_get_dqblk);
|
||||
|
||||
#define VFS_FS_DQ_MASK \
|
||||
(FS_DQ_BCOUNT | FS_DQ_BSOFT | FS_DQ_BHARD | \
|
||||
FS_DQ_ICOUNT | FS_DQ_ISOFT | FS_DQ_IHARD | \
|
||||
FS_DQ_BTIMER | FS_DQ_ITIMER)
|
||||
#define VFS_QC_MASK \
|
||||
(QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \
|
||||
QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \
|
||||
QC_SPC_TIMER | QC_INO_TIMER)
|
||||
|
||||
/* 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;
|
||||
int check_blim = 0, check_ilim = 0;
|
||||
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;
|
||||
|
||||
if (((di->d_fieldmask & FS_DQ_BSOFT) &&
|
||||
(di->d_blk_softlimit > dqi->dqi_maxblimit)) ||
|
||||
((di->d_fieldmask & FS_DQ_BHARD) &&
|
||||
(di->d_blk_hardlimit > dqi->dqi_maxblimit)) ||
|
||||
((di->d_fieldmask & FS_DQ_ISOFT) &&
|
||||
if (((di->d_fieldmask & QC_SPC_SOFT) &&
|
||||
stoqb(di->d_spc_softlimit) > dqi->dqi_maxblimit) ||
|
||||
((di->d_fieldmask & QC_SPC_HARD) &&
|
||||
stoqb(di->d_spc_hardlimit) > dqi->dqi_maxblimit) ||
|
||||
((di->d_fieldmask & QC_INO_SOFT) &&
|
||||
(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)))
|
||||
return -ERANGE;
|
||||
|
||||
spin_lock(&dq_data_lock);
|
||||
if (di->d_fieldmask & FS_DQ_BCOUNT) {
|
||||
dm->dqb_curspace = di->d_bcount - dm->dqb_rsvspace;
|
||||
if (di->d_fieldmask & QC_SPACE) {
|
||||
dm->dqb_curspace = di->d_space - dm->dqb_rsvspace;
|
||||
check_blim = 1;
|
||||
set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
|
||||
}
|
||||
|
||||
if (di->d_fieldmask & FS_DQ_BSOFT)
|
||||
dm->dqb_bsoftlimit = qbtos(di->d_blk_softlimit);
|
||||
if (di->d_fieldmask & FS_DQ_BHARD)
|
||||
dm->dqb_bhardlimit = qbtos(di->d_blk_hardlimit);
|
||||
if (di->d_fieldmask & (FS_DQ_BSOFT | FS_DQ_BHARD)) {
|
||||
if (di->d_fieldmask & QC_SPC_SOFT)
|
||||
dm->dqb_bsoftlimit = di->d_spc_softlimit;
|
||||
if (di->d_fieldmask & QC_SPC_HARD)
|
||||
dm->dqb_bhardlimit = di->d_spc_hardlimit;
|
||||
if (di->d_fieldmask & (QC_SPC_SOFT | QC_SPC_HARD)) {
|
||||
check_blim = 1;
|
||||
set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
|
||||
}
|
||||
|
||||
if (di->d_fieldmask & FS_DQ_ICOUNT) {
|
||||
dm->dqb_curinodes = di->d_icount;
|
||||
if (di->d_fieldmask & QC_INO_COUNT) {
|
||||
dm->dqb_curinodes = di->d_ino_count;
|
||||
check_ilim = 1;
|
||||
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;
|
||||
if (di->d_fieldmask & FS_DQ_IHARD)
|
||||
if (di->d_fieldmask & QC_INO_HARD)
|
||||
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;
|
||||
set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
|
||||
}
|
||||
|
||||
if (di->d_fieldmask & FS_DQ_BTIMER) {
|
||||
dm->dqb_btime = di->d_btimer;
|
||||
if (di->d_fieldmask & QC_SPC_TIMER) {
|
||||
dm->dqb_btime = di->d_spc_timer;
|
||||
check_blim = 1;
|
||||
set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
|
||||
}
|
||||
|
||||
if (di->d_fieldmask & FS_DQ_ITIMER) {
|
||||
dm->dqb_itime = di->d_itimer;
|
||||
if (di->d_fieldmask & QC_INO_TIMER) {
|
||||
dm->dqb_itime = di->d_ino_timer;
|
||||
check_ilim = 1;
|
||||
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_btime = 0;
|
||||
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... */
|
||||
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_itime = 0;
|
||||
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... */
|
||||
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,
|
||||
struct fs_disk_quota *di)
|
||||
struct qc_dqblk *di)
|
||||
{
|
||||
struct dquot *dquot;
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
dst->dqb_bhardlimit = src->d_blk_hardlimit;
|
||||
dst->dqb_bsoftlimit = src->d_blk_softlimit;
|
||||
dst->dqb_curspace = src->d_bcount;
|
||||
dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
|
||||
dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
|
||||
dst->dqb_curspace = src->d_space;
|
||||
dst->dqb_ihardlimit = src->d_ino_hardlimit;
|
||||
dst->dqb_isoftlimit = src->d_ino_softlimit;
|
||||
dst->dqb_curinodes = src->d_icount;
|
||||
dst->dqb_btime = src->d_btimer;
|
||||
dst->dqb_itime = src->d_itimer;
|
||||
dst->dqb_curinodes = src->d_ino_count;
|
||||
dst->dqb_btime = src->d_spc_timer;
|
||||
dst->dqb_itime = src->d_ino_timer;
|
||||
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)
|
||||
{
|
||||
struct kqid qid;
|
||||
struct fs_disk_quota fdq;
|
||||
struct qc_dqblk fdq;
|
||||
struct if_dqblk idq;
|
||||
int ret;
|
||||
|
||||
@@ -154,36 +164,36 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
|
||||
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_blk_softlimit = src->dqb_bsoftlimit;
|
||||
dst->d_bcount = src->dqb_curspace;
|
||||
dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
|
||||
dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
|
||||
dst->d_space = src->dqb_curspace;
|
||||
dst->d_ino_hardlimit = src->dqb_ihardlimit;
|
||||
dst->d_ino_softlimit = src->dqb_isoftlimit;
|
||||
dst->d_icount = src->dqb_curinodes;
|
||||
dst->d_btimer = src->dqb_btime;
|
||||
dst->d_itimer = src->dqb_itime;
|
||||
dst->d_ino_count = src->dqb_curinodes;
|
||||
dst->d_spc_timer = src->dqb_btime;
|
||||
dst->d_ino_timer = src->dqb_itime;
|
||||
|
||||
dst->d_fieldmask = 0;
|
||||
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)
|
||||
dst->d_fieldmask |= FS_DQ_BCOUNT;
|
||||
dst->d_fieldmask |= QC_SPACE;
|
||||
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)
|
||||
dst->d_fieldmask |= FS_DQ_ICOUNT;
|
||||
dst->d_fieldmask |= QC_INO_COUNT;
|
||||
if (src->dqb_valid & QIF_BTIME)
|
||||
dst->d_fieldmask |= FS_DQ_BTIMER;
|
||||
dst->d_fieldmask |= QC_SPC_TIMER;
|
||||
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,
|
||||
void __user *addr)
|
||||
{
|
||||
struct fs_disk_quota fdq;
|
||||
struct qc_dqblk fdq;
|
||||
struct if_dqblk idq;
|
||||
struct kqid qid;
|
||||
|
||||
@@ -247,10 +257,78 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr)
|
||||
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,
|
||||
void __user *addr)
|
||||
{
|
||||
struct fs_disk_quota fdq;
|
||||
struct qc_dqblk qdq;
|
||||
struct kqid qid;
|
||||
|
||||
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);
|
||||
if (!qid_valid(qid))
|
||||
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,
|
||||
void __user *addr)
|
||||
{
|
||||
struct fs_disk_quota fdq;
|
||||
struct qc_dqblk qdq;
|
||||
struct kqid qid;
|
||||
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);
|
||||
if (!qid_valid(qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
|
||||
if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
|
||||
ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
|
||||
if (ret)
|
||||
return ret;
|
||||
copy_to_xfs_dqblk(&fdq, &qdq, type, id);
|
||||
if (copy_to_user(addr, &fdq, sizeof(fdq)))
|
||||
return -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user