--- /dev/null
+From 14bf61ffe6ac54afcd1e888a4407fe16054483db Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Thu, 9 Oct 2014 16:03:13 +0200
+Subject: quota: Switch ->get_dqblk() and ->set_dqblk() to use bytes as space units
+
+From: Jan Kara <jack@suse.cz>
+
+commit 14bf61ffe6ac54afcd1e888a4407fe16054483db upstream.
+
+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.
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/gfs2/quota.c | 53 +++++++--------
+ fs/quota/dquot.c | 83 +++++++++++-------------
+ fs/quota/quota.c | 162 +++++++++++++++++++++++++++++++++++++++--------
+ fs/xfs/xfs_qm.h | 4 -
+ fs/xfs/xfs_qm_syscalls.c | 156 +++++++++++++++++++--------------------------
+ fs/xfs/xfs_quotaops.c | 8 +-
+ include/linux/quota.h | 47 +++++++++++++
+ include/linux/quotaops.h | 4 -
+ 8 files changed, 320 insertions(+), 197 deletions(-)
+
+--- a/fs/gfs2/quota.c
++++ b/fs/gfs2/quota.c
+@@ -667,7 +667,7 @@ static void do_qc(struct gfs2_quota_data
+
+ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ s64 change, struct gfs2_quota_data *qd,
+- struct fs_disk_quota *fdq)
++ struct qc_dqblk *fdq)
+ {
+ struct inode *inode = &ip->i_inode;
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+@@ -697,16 +697,16 @@ static int gfs2_adjust_quota(struct gfs2
+ be64_add_cpu(&q.qu_value, change);
+ qd->qd_qb.qb_value = q.qu_value;
+ if (fdq) {
+- if (fdq->d_fieldmask & FS_DQ_BSOFT) {
+- q.qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift);
++ if (fdq->d_fieldmask & QC_SPC_SOFT) {
++ q.qu_warn = cpu_to_be64(fdq->d_spc_softlimit >> sdp->sd_sb.sb_bsize_shift);
+ qd->qd_qb.qb_warn = q.qu_warn;
+ }
+- if (fdq->d_fieldmask & FS_DQ_BHARD) {
+- q.qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift);
++ if (fdq->d_fieldmask & QC_SPC_HARD) {
++ q.qu_limit = cpu_to_be64(fdq->d_spc_hardlimit >> sdp->sd_sb.sb_bsize_shift);
+ qd->qd_qb.qb_limit = q.qu_limit;
+ }
+- if (fdq->d_fieldmask & FS_DQ_BCOUNT) {
+- q.qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift);
++ if (fdq->d_fieldmask & QC_SPACE) {
++ q.qu_value = cpu_to_be64(fdq->d_space >> sdp->sd_sb.sb_bsize_shift);
+ qd->qd_qb.qb_value = q.qu_value;
+ }
+ }
+@@ -1502,7 +1502,7 @@ static int gfs2_quota_get_xstate(struct
+ }
+
+ 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_quota_lvb *qlvb;
+@@ -1510,7 +1510,7 @@ static int gfs2_get_dqblk(struct super_b
+ struct gfs2_holder q_gh;
+ int error;
+
+- memset(fdq, 0, sizeof(struct fs_disk_quota));
++ memset(fdq, 0, sizeof(*fdq));
+
+ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
+ return -ESRCH; /* Crazy XFS error code */
+@@ -1527,12 +1527,9 @@ static int gfs2_get_dqblk(struct super_b
+ goto out;
+
+ qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;
+- fdq->d_version = FS_DQUOT_VERSION;
+- fdq->d_flags = (qid.type == USRQUOTA) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
+- fdq->d_id = from_kqid_munged(current_user_ns(), qid);
+- 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;
++ fdq->d_spc_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_sb.sb_bsize_shift;
++ fdq->d_spc_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_sb.sb_bsize_shift;
++ fdq->d_space = be64_to_cpu(qlvb->qb_value) << sdp->sd_sb.sb_bsize_shift;
+
+ gfs2_glock_dq_uninit(&q_gh);
+ out:
+@@ -1541,10 +1538,10 @@ out:
+ }
+
+ /* 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,
+- struct fs_disk_quota *fdq)
++ struct qc_dqblk *fdq)
+ {
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+@@ -1588,17 +1585,17 @@ static int gfs2_set_dqblk(struct super_b
+ goto out_i;
+
+ /* If nothing has changed, this is a no-op */
+- if ((fdq->d_fieldmask & FS_DQ_BSOFT) &&
+- ((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
+- fdq->d_fieldmask ^= FS_DQ_BSOFT;
+-
+- if ((fdq->d_fieldmask & FS_DQ_BHARD) &&
+- ((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
+- fdq->d_fieldmask ^= FS_DQ_BHARD;
+-
+- if ((fdq->d_fieldmask & FS_DQ_BCOUNT) &&
+- ((fdq->d_bcount >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_value)))
+- fdq->d_fieldmask ^= FS_DQ_BCOUNT;
++ if ((fdq->d_fieldmask & QC_SPC_SOFT) &&
++ ((fdq->d_spc_softlimit >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
++ fdq->d_fieldmask ^= QC_SPC_SOFT;
++
++ if ((fdq->d_fieldmask & QC_SPC_HARD) &&
++ ((fdq->d_spc_hardlimit >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
++ fdq->d_fieldmask ^= QC_SPC_HARD;
++
++ if ((fdq->d_fieldmask & QC_SPACE) &&
++ ((fdq->d_space >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_value)))
++ fdq->d_fieldmask ^= QC_SPACE;
+
+ if (fdq->d_fieldmask == 0)
+ goto out_i;
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -2391,30 +2391,25 @@ static inline qsize_t stoqb(qsize_t spac
+ }
+
+ /* 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;
+
+@@ -2428,70 +2423,70 @@ int dquot_get_dqblk(struct super_block *
+ }
+ 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);
+ }
+@@ -2501,7 +2496,7 @@ static int do_set_dqblk(struct dquot *dq
+ 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;
+ }
+@@ -2510,7 +2505,7 @@ static int do_set_dqblk(struct dquot *dq
+ 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;
+ }
+@@ -2526,7 +2521,7 @@ static int do_set_dqblk(struct dquot *dq
+ }
+
+ 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;
+--- a/fs/quota/quota.c
++++ b/fs/quota/quota.c
+@@ -115,17 +115,27 @@ static int quota_setinfo(struct super_bl
+ 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;
+ }
+
+@@ -133,7 +143,7 @@ static int quota_getquota(struct super_b
+ void __user *addr)
+ {
+ struct kqid qid;
+- struct fs_disk_quota fdq;
++ struct qc_dqblk fdq;
+ struct if_dqblk idq;
+ int ret;
+
+@@ -151,36 +161,36 @@ static int quota_getquota(struct super_b
+ 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;
+
+@@ -244,10 +254,78 @@ static int quota_getxstatev(struct super
+ 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)))
+@@ -257,13 +335,44 @@ static int quota_setxquota(struct super_
+ 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;
+
+@@ -272,8 +381,11 @@ static int quota_getxquota(struct super_
+ 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;
+ }
+--- a/fs/xfs/xfs_qm.h
++++ b/fs/xfs/xfs_qm.h
+@@ -166,9 +166,9 @@ extern void xfs_qm_dqrele_all_inodes(st
+ /* quota ops */
+ extern int xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
+ 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,
+- struct fs_disk_quota *);
++ struct qc_dqblk *);
+ extern int xfs_qm_scall_getqstat(struct xfs_mount *,
+ struct fs_quota_stat *);
+ extern int xfs_qm_scall_getqstatv(struct xfs_mount *,
+--- a/fs/xfs/xfs_qm_syscalls.c
++++ b/fs/xfs/xfs_qm_syscalls.c
+@@ -40,7 +40,6 @@ STATIC int xfs_qm_log_quotaoff(xfs_mount
+ STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
+ 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
+@@ -574,8 +573,8 @@ xfs_qm_scall_getqstatv(
+ return 0;
+ }
+
+-#define XFS_DQ_MASK \
+- (FS_DQ_LIMIT_MASK | FS_DQ_TIMER_MASK | FS_DQ_WARNS_MASK)
++#define XFS_QC_MASK \
++ (QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK)
+
+ /*
+ * Adjust quota limits, and start/stop timers accordingly.
+@@ -585,7 +584,7 @@ xfs_qm_scall_setqlim(
+ struct xfs_mount *mp,
+ xfs_dqid_t id,
+ uint type,
+- fs_disk_quota_t *newlim)
++ struct qc_dqblk *newlim)
+ {
+ struct xfs_quotainfo *q = mp->m_quotainfo;
+ struct xfs_disk_dquot *ddq;
+@@ -594,9 +593,9 @@ xfs_qm_scall_setqlim(
+ int error;
+ xfs_qcnt_t hard, soft;
+
+- if (newlim->d_fieldmask & ~XFS_DQ_MASK)
++ if (newlim->d_fieldmask & ~XFS_QC_MASK)
+ return -EINVAL;
+- if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)
++ if ((newlim->d_fieldmask & XFS_QC_MASK) == 0)
+ return 0;
+
+ /*
+@@ -634,11 +633,11 @@ xfs_qm_scall_setqlim(
+ /*
+ * Make sure that hardlimits are >= soft limits before changing.
+ */
+- hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
+- (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
++ hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
++ (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
+ be64_to_cpu(ddq->d_blk_hardlimit);
+- soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
+- (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
++ soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
++ (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
+ be64_to_cpu(ddq->d_blk_softlimit);
+ if (hard == 0 || hard >= soft) {
+ ddq->d_blk_hardlimit = cpu_to_be64(hard);
+@@ -651,11 +650,11 @@ xfs_qm_scall_setqlim(
+ } else {
+ xfs_debug(mp, "blkhard %Ld < blksoft %Ld", hard, soft);
+ }
+- hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
+- (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
++ hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
++ (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
+ be64_to_cpu(ddq->d_rtb_hardlimit);
+- soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
+- (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
++ soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
++ (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
+ be64_to_cpu(ddq->d_rtb_softlimit);
+ if (hard == 0 || hard >= soft) {
+ ddq->d_rtb_hardlimit = cpu_to_be64(hard);
+@@ -668,10 +667,10 @@ xfs_qm_scall_setqlim(
+ 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 :
+ 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 :
+ be64_to_cpu(ddq->d_ino_softlimit);
+ if (hard == 0 || hard >= soft) {
+@@ -688,12 +687,12 @@ xfs_qm_scall_setqlim(
+ /*
+ * Update warnings counter(s) if requested
+ */
+- if (newlim->d_fieldmask & FS_DQ_BWARNS)
+- ddq->d_bwarns = cpu_to_be16(newlim->d_bwarns);
+- if (newlim->d_fieldmask & FS_DQ_IWARNS)
+- ddq->d_iwarns = cpu_to_be16(newlim->d_iwarns);
+- if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
+- ddq->d_rtbwarns = cpu_to_be16(newlim->d_rtbwarns);
++ if (newlim->d_fieldmask & QC_SPC_WARNS)
++ ddq->d_bwarns = cpu_to_be16(newlim->d_spc_warns);
++ if (newlim->d_fieldmask & QC_INO_WARNS)
++ ddq->d_iwarns = cpu_to_be16(newlim->d_ino_warns);
++ if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
++ ddq->d_rtbwarns = cpu_to_be16(newlim->d_rt_spc_warns);
+
+ if (id == 0) {
+ /*
+@@ -703,24 +702,24 @@ xfs_qm_scall_setqlim(
+ * soft and hard limit values (already done, above), and
+ * for warnings.
+ */
+- if (newlim->d_fieldmask & FS_DQ_BTIMER) {
+- q->qi_btimelimit = newlim->d_btimer;
+- ddq->d_btimer = cpu_to_be32(newlim->d_btimer);
++ if (newlim->d_fieldmask & QC_SPC_TIMER) {
++ q->qi_btimelimit = newlim->d_spc_timer;
++ ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
+ }
+- if (newlim->d_fieldmask & FS_DQ_ITIMER) {
+- q->qi_itimelimit = newlim->d_itimer;
+- ddq->d_itimer = cpu_to_be32(newlim->d_itimer);
++ if (newlim->d_fieldmask & QC_INO_TIMER) {
++ q->qi_itimelimit = newlim->d_ino_timer;
++ ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
+ }
+- if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
+- q->qi_rtbtimelimit = newlim->d_rtbtimer;
+- ddq->d_rtbtimer = cpu_to_be32(newlim->d_rtbtimer);
++ if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
++ q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
++ ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
+ }
+- if (newlim->d_fieldmask & FS_DQ_BWARNS)
+- q->qi_bwarnlimit = newlim->d_bwarns;
+- if (newlim->d_fieldmask & FS_DQ_IWARNS)
+- q->qi_iwarnlimit = newlim->d_iwarns;
+- if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
+- q->qi_rtbwarnlimit = newlim->d_rtbwarns;
++ if (newlim->d_fieldmask & QC_SPC_WARNS)
++ q->qi_bwarnlimit = newlim->d_spc_warns;
++ if (newlim->d_fieldmask & QC_INO_WARNS)
++ q->qi_iwarnlimit = newlim->d_ino_warns;
++ if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
++ q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
+ } else {
+ /*
+ * If the user is now over quota, start the timelimit.
+@@ -831,7 +830,7 @@ xfs_qm_scall_getquota(
+ struct xfs_mount *mp,
+ xfs_dqid_t id,
+ uint type,
+- struct fs_disk_quota *dst)
++ struct qc_dqblk *dst)
+ {
+ struct xfs_dquot *dqp;
+ int error;
+@@ -855,28 +854,25 @@ xfs_qm_scall_getquota(
+ }
+
+ memset(dst, 0, sizeof(*dst));
+- dst->d_version = FS_DQUOT_VERSION;
+- dst->d_flags = xfs_qm_export_qtype_flags(dqp->q_core.d_flags);
+- dst->d_id = be32_to_cpu(dqp->q_core.d_id);
+- dst->d_blk_hardlimit =
+- 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_spc_hardlimit =
++ XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
++ dst->d_spc_softlimit =
++ XFS_FSB_TO_B(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_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
+- dst->d_bcount = XFS_FSB_TO_BB(mp, dqp->q_res_bcount);
+- dst->d_icount = dqp->q_res_icount;
+- dst->d_btimer = be32_to_cpu(dqp->q_core.d_btimer);
+- dst->d_itimer = be32_to_cpu(dqp->q_core.d_itimer);
+- dst->d_iwarns = be16_to_cpu(dqp->q_core.d_iwarns);
+- dst->d_bwarns = be16_to_cpu(dqp->q_core.d_bwarns);
+- dst->d_rtb_hardlimit =
+- XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
+- dst->d_rtb_softlimit =
+- XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
+- dst->d_rtbcount = XFS_FSB_TO_BB(mp, dqp->q_res_rtbcount);
+- dst->d_rtbtimer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+- dst->d_rtbwarns = be16_to_cpu(dqp->q_core.d_rtbwarns);
++ dst->d_space = XFS_FSB_TO_B(mp, dqp->q_res_bcount);
++ dst->d_ino_count = dqp->q_res_icount;
++ dst->d_spc_timer = be32_to_cpu(dqp->q_core.d_btimer);
++ dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer);
++ dst->d_ino_warns = be16_to_cpu(dqp->q_core.d_iwarns);
++ dst->d_spc_warns = be16_to_cpu(dqp->q_core.d_bwarns);
++ dst->d_rt_spc_hardlimit =
++ XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
++ dst->d_rt_spc_softlimit =
++ XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
++ dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_res_rtbcount);
++ dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
++ dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
+
+ /*
+ * Internally, we don't reset all the timers when quota enforcement
+@@ -889,23 +885,23 @@ xfs_qm_scall_getquota(
+ dqp->q_core.d_flags == XFS_DQ_GROUP) ||
+ (!XFS_IS_PQUOTA_ENFORCED(mp) &&
+ dqp->q_core.d_flags == XFS_DQ_PROJ)) {
+- dst->d_btimer = 0;
+- dst->d_itimer = 0;
+- dst->d_rtbtimer = 0;
++ dst->d_spc_timer = 0;
++ dst->d_ino_timer = 0;
++ dst->d_rt_spc_timer = 0;
+ }
+
+ #ifdef DEBUG
+- if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
+- (XFS_IS_GQUOTA_ENFORCED(mp) && dst->d_flags == FS_GROUP_QUOTA) ||
+- (XFS_IS_PQUOTA_ENFORCED(mp) && dst->d_flags == FS_PROJ_QUOTA)) &&
+- dst->d_id != 0) {
+- if ((dst->d_bcount > dst->d_blk_softlimit) &&
+- (dst->d_blk_softlimit > 0)) {
+- ASSERT(dst->d_btimer != 0);
++ if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
++ (XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
++ (XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
++ id != 0) {
++ if ((dst->d_space > dst->d_spc_softlimit) &&
++ (dst->d_spc_softlimit > 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)) {
+- ASSERT(dst->d_itimer != 0);
++ ASSERT(dst->d_ino_timer != 0);
+ }
+ }
+ #endif
+@@ -915,26 +911,6 @@ out_put:
+ }
+
+ 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
+ xfs_qm_export_flags(
+ uint flags)
+ {
+--- a/fs/xfs/xfs_quotaops.c
++++ b/fs/xfs/xfs_quotaops.c
+@@ -133,7 +133,7 @@ STATIC int
+ xfs_fs_get_dqblk(
+ struct super_block *sb,
+ struct kqid qid,
+- struct fs_disk_quota *fdq)
++ struct qc_dqblk *qdq)
+ {
+ struct xfs_mount *mp = XFS_M(sb);
+
+@@ -143,14 +143,14 @@ xfs_fs_get_dqblk(
+ return -ESRCH;
+
+ 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
+ xfs_fs_set_dqblk(
+ struct super_block *sb,
+ struct kqid qid,
+- struct fs_disk_quota *fdq)
++ struct qc_dqblk *qdq)
+ {
+ struct xfs_mount *mp = XFS_M(sb);
+
+@@ -162,7 +162,7 @@ xfs_fs_set_dqblk(
+ return -ESRCH;
+
+ 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 = {
+--- a/include/linux/quota.h
++++ b/include/linux/quota.h
+@@ -316,6 +316,49 @@ struct dquot_operations {
+
+ 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 */
+ struct quotactl_ops {
+ int (*quota_on)(struct super_block *, int, int, struct path *);
+@@ -324,8 +367,8 @@ struct quotactl_ops {
+ int (*quota_sync)(struct super_block *, int);
+ int (*get_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 (*set_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 qc_dqblk *);
+ int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
+ int (*set_xstate)(struct super_block *, unsigned int, int);
+ int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
+--- a/include/linux/quotaops.h
++++ b/include/linux/quotaops.h
+@@ -98,9 +98,9 @@ int dquot_quota_sync(struct super_block
+ 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_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,
+- 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 iattr *iattr);