quota: Switch ->get_dqblk() and ->set_dqblk() to use bytes as space units
[firefly-linux-kernel-4.4.55.git] / fs / quota / quota.c
index 2aa4151f99d2e5e9183adfb34e2c31da24e2faa2..6f3856328eeabd4bbc57b09ca9c8fe01a9827c9c 100644 (file)
@@ -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;
 }