quota: unify ->set_dqblk
authorChristoph Hellwig <hch@infradead.org>
Thu, 6 May 2010 21:05:17 +0000 (17:05 -0400)
committerJan Kara <jack@suse.cz>
Fri, 21 May 2010 17:30:44 +0000 (19:30 +0200)
Pass the larger struct fs_disk_quota to the ->set_dqblk operation so
that the Q_SETQUOTA and Q_XSETQUOTA operations can be implemented
with a single filesystem operation and we can retire the ->set_xquota
operation.  The additional information (RT-subvolume accounting and
warn counts) are left zero for the VFS quota implementation.

Add new fieldmask values for setting the numer of blocks and inodes
values which is required for the VFS quota, but wasn't for XFS.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/gfs2/quota.c
fs/quota/dquot.c
fs/quota/quota.c
fs/xfs/linux-2.6/xfs_quotaops.c
fs/xfs/quota/xfs_qm_syscalls.c
include/linux/dqblk_xfs.h
include/linux/quota.h
include/linux/quotaops.h

index dec93577a7839cecbe166313692799aecdafaa6a..49667d68769ef8fe5a82920a79f1a37df216804b 100644 (file)
@@ -1521,8 +1521,8 @@ out:
 /* GFS2 only supports a subset of the XFS fields */
 #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD)
 
-static int gfs2_xquota_set(struct super_block *sb, int type, qid_t id,
-                          struct fs_disk_quota *fdq)
+static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
+                         struct fs_disk_quota *fdq)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1630,6 +1630,6 @@ const struct quotactl_ops gfs2_quotactl_ops = {
        .quota_sync     = gfs2_quota_sync,
        .get_xstate     = gfs2_quota_get_xstate,
        .get_dqblk      = gfs2_get_dqblk,
-       .set_xquota     = gfs2_xquota_set,
+       .set_dqblk      = gfs2_set_dqblk,
 };
 
index 6aed77fc99c778e8e3386b00a8088e35950b10ac..b1a5036560a94aa2101310a8e6eb94e1ca86f2f3 100644 (file)
@@ -2338,51 +2338,70 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
 }
 EXPORT_SYMBOL(vfs_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)
+
 /* Generic routine for setting common part of quota structure */
-static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *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_type];
 
-       if ((di->dqb_valid & QIF_BLIMITS &&
-            (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
-             di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
-           (di->dqb_valid & QIF_ILIMITS &&
-            (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
-             di->dqb_isoftlimit > dqi->dqi_maxilimit)))
+       if (di->d_fieldmask & ~VFS_FS_DQ_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) &&
+            (di->d_ino_softlimit > dqi->dqi_maxilimit)) ||
+           ((di->d_fieldmask & FS_DQ_IHARD) &&
+            (di->d_ino_hardlimit > dqi->dqi_maxilimit)))
                return -ERANGE;
 
        spin_lock(&dq_data_lock);
-       if (di->dqb_valid & QIF_SPACE) {
-               dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
+       if (di->d_fieldmask & FS_DQ_BCOUNT) {
+               dm->dqb_curspace = di->d_bcount - dm->dqb_rsvspace;
                check_blim = 1;
                set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
        }
-       if (di->dqb_valid & QIF_BLIMITS) {
-               dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit);
-               dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit);
+
+       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)) {
                check_blim = 1;
                set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
        }
-       if (di->dqb_valid & QIF_INODES) {
-               dm->dqb_curinodes = di->dqb_curinodes;
+
+       if (di->d_fieldmask & FS_DQ_ICOUNT) {
+               dm->dqb_curinodes = di->d_icount;
                check_ilim = 1;
                set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
        }
-       if (di->dqb_valid & QIF_ILIMITS) {
-               dm->dqb_isoftlimit = di->dqb_isoftlimit;
-               dm->dqb_ihardlimit = di->dqb_ihardlimit;
+
+       if (di->d_fieldmask & FS_DQ_ISOFT)
+               dm->dqb_isoftlimit = di->d_ino_softlimit;
+       if (di->d_fieldmask & FS_DQ_IHARD)
+               dm->dqb_ihardlimit = di->d_ino_hardlimit;
+       if (di->d_fieldmask & (FS_DQ_ISOFT | FS_DQ_IHARD)) {
                check_ilim = 1;
                set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
        }
-       if (di->dqb_valid & QIF_BTIME) {
-               dm->dqb_btime = di->dqb_btime;
+
+       if (di->d_fieldmask & FS_DQ_BTIMER) {
+               dm->dqb_btime = di->d_btimer;
                check_blim = 1;
                set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
        }
-       if (di->dqb_valid & QIF_ITIME) {
-               dm->dqb_itime = di->dqb_itime;
+
+       if (di->d_fieldmask & FS_DQ_ITIMER) {
+               dm->dqb_itime = di->d_itimer;
                check_ilim = 1;
                set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
        }
@@ -2392,7 +2411,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
                    dm->dqb_curspace < dm->dqb_bsoftlimit) {
                        dm->dqb_btime = 0;
                        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
-               } else if (!(di->dqb_valid & QIF_BTIME))
+               } else if (!(di->d_fieldmask & FS_DQ_BTIMER))
                        /* Set grace only if user hasn't provided his own... */
                        dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
        }
@@ -2401,7 +2420,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
                    dm->dqb_curinodes < dm->dqb_isoftlimit) {
                        dm->dqb_itime = 0;
                        clear_bit(DQ_INODES_B, &dquot->dq_flags);
-               } else if (!(di->dqb_valid & QIF_ITIME))
+               } else if (!(di->d_fieldmask & FS_DQ_ITIMER))
                        /* Set grace only if user hasn't provided his own... */
                        dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
        }
@@ -2417,7 +2436,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
 }
 
 int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
-                 struct if_dqblk *di)
+                 struct fs_disk_quota *di)
 {
        struct dquot *dquot;
        int rc;
index 8680e257c2bdb315a81443da396bfde2620e5aa0..d6ee49dda4fd1a4bd61ab0002c46bf45effeca21 100644 (file)
@@ -167,18 +167,44 @@ 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)
+{
+       dst->d_blk_hardlimit = src->dqb_bhardlimit;
+       dst->d_blk_softlimit  = src->dqb_bsoftlimit;
+       dst->d_bcount = 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_fieldmask = 0;
+       if (src->dqb_valid & QIF_BLIMITS)
+               dst->d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
+       if (src->dqb_valid & QIF_SPACE)
+               dst->d_fieldmask |= FS_DQ_BCOUNT;
+       if (src->dqb_valid & QIF_ILIMITS)
+               dst->d_fieldmask |= FS_DQ_ISOFT | FS_DQ_IHARD;
+       if (src->dqb_valid & QIF_INODES)
+               dst->d_fieldmask |= FS_DQ_ICOUNT;
+       if (src->dqb_valid & QIF_BTIME)
+               dst->d_fieldmask |= FS_DQ_BTIMER;
+       if (src->dqb_valid & QIF_ITIME)
+               dst->d_fieldmask |= FS_DQ_ITIMER;
+}
+
 static int quota_setquota(struct super_block *sb, int type, qid_t id,
                          void __user *addr)
 {
+       struct fs_disk_quota fdq;
        struct if_dqblk idq;
 
        if (copy_from_user(&idq, addr, sizeof(idq)))
                return -EFAULT;
-       if (!sb_has_quota_active(sb, type))
-               return -ESRCH;
        if (!sb->s_qcop->set_dqblk)
                return -ENOSYS;
-       return sb->s_qcop->set_dqblk(sb, type, id, &idq);
+       copy_from_if_dqblk(&fdq, &idq);
+       return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
 }
 
 static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
@@ -212,9 +238,9 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
 
        if (copy_from_user(&fdq, addr, sizeof(fdq)))
                return -EFAULT;
-       if (!sb->s_qcop->set_xquota)
+       if (!sb->s_qcop->set_dqblk)
                return -ENOSYS;
-       return sb->s_qcop->set_xquota(sb, type, id, &fdq);
+       return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
 }
 
 static int quota_getxquota(struct super_block *sb, int type, qid_t id,
index 3d473f43c9a92e11f2afc2deadefae48138f590b..e31bf21fe5d33840ce1fbd352e625c2558dde1a2 100644 (file)
@@ -114,7 +114,7 @@ xfs_fs_get_dqblk(
 }
 
 STATIC int
-xfs_fs_set_xquota(
+xfs_fs_set_dqblk(
        struct super_block      *sb,
        int                     type,
        qid_t                   id,
@@ -136,5 +136,5 @@ const struct quotactl_ops xfs_quotactl_operations = {
        .get_xstate             = xfs_fs_get_xstate,
        .set_xstate             = xfs_fs_set_xstate,
        .get_dqblk              = xfs_fs_get_dqblk,
-       .set_xquota             = xfs_fs_set_xquota,
+       .set_dqblk              = xfs_fs_set_dqblk,
 };
index 26fa43140f2e7d6c6fa62e19f9a079724f4866d4..92b002f1805fdc85c237ea295728a6bc44dd8986 100644 (file)
@@ -448,6 +448,9 @@ xfs_qm_scall_getqstat(
        return 0;
 }
 
+#define XFS_DQ_MASK \
+       (FS_DQ_LIMIT_MASK | FS_DQ_TIMER_MASK | FS_DQ_WARNS_MASK)
+
 /*
  * Adjust quota limits, and start/stop timers accordingly.
  */
@@ -465,9 +468,10 @@ xfs_qm_scall_setqlim(
        int                     error;
        xfs_qcnt_t              hard, soft;
 
-       if ((newlim->d_fieldmask &
-           (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK|FS_DQ_WARNS_MASK)) == 0)
-               return (0);
+       if (newlim->d_fieldmask & ~XFS_DQ_MASK)
+               return EINVAL;
+       if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)
+               return 0;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
        if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
index 527504c11c5e810b9848bcfc2dc480028bc103a5..4389ae72024e73cfc48e7389e988c2d15ce81b22 100644 (file)
@@ -109,6 +109,15 @@ typedef struct fs_disk_quota {
 #define FS_DQ_RTBWARNS (1<<11)
 #define FS_DQ_WARNS_MASK       (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS)
 
+/*
+ * Accounting values.  These can only be set for filesystem with
+ * non-transactional quotas that require quotacheck(8) in userspace.
+ */
+#define FS_DQ_BCOUNT           (1<<12)
+#define FS_DQ_ICOUNT           (1<<13)
+#define FS_DQ_RTBCOUNT         (1<<14)
+#define FS_DQ_ACCT_MASK                (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
+
 /*
  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
  */
index 42364219dc9b9385128a41b2f75d3fd0e3ffc208..7126a15467f19a1238cabdc3b9eccc237b9d0ad9 100644 (file)
@@ -338,10 +338,9 @@ struct quotactl_ops {
        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 *, int, qid_t, struct fs_disk_quota *);
-       int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+       int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
        int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
        int (*set_xstate)(struct super_block *, unsigned int, int);
-       int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
 };
 
 struct quota_format_type {
index d32a48631b0d8c340fc158f6bd6c001d22edf05a..82c70c42d0353de628631be1236b67a429f3fb7f 100644 (file)
@@ -65,7 +65,8 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
                struct fs_disk_quota *di);
-int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di);
+int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
+               struct fs_disk_quota *di);
 
 int dquot_transfer(struct inode *inode, struct iattr *iattr);
 int vfs_dq_quota_on_remount(struct super_block *sb);