quota: Make VFS quotas use new interface for getting quota info
authorJan Kara <jack@suse.cz>
Tue, 18 Nov 2014 23:42:09 +0000 (00:42 +0100)
committerJan Kara <jack@suse.cz>
Wed, 4 Mar 2015 15:06:34 +0000 (16:06 +0100)
Create new internal interface for getting information about quota which
contains everything needed for both VFS quotas and XFS quotas. Make VFS
use this and hook it up to Q_GETINFO.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/ext3/super.c
fs/ext4/super.c
fs/quota/dquot.c
fs/quota/quota.c
fs/reiserfs/super.c
include/linux/quota.h
include/linux/quotaops.h

index d4dbf3c259b3288a961304daff37d7e1a848e43f..f037b4b273002f5a6815da593cad35f59b81b890 100644 (file)
@@ -789,7 +789,7 @@ static const struct quotactl_ops ext3_qctl_operations = {
        .quota_on       = ext3_quota_on,
        .quota_off      = dquot_quota_off,
        .quota_sync     = dquot_quota_sync,
-       .get_info       = dquot_get_dqinfo,
+       .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
        .set_dqblk      = dquot_set_dqblk
index e061e66c82800f700b7642e4c82fa2cc836be05f..d348c7d29d801d92dfba884b0ca188b26e84fbf9 100644 (file)
@@ -1076,7 +1076,7 @@ static const struct quotactl_ops ext4_qctl_operations = {
        .quota_on       = ext4_quota_on,
        .quota_off      = ext4_quota_off,
        .quota_sync     = dquot_quota_sync,
-       .get_info       = dquot_get_dqinfo,
+       .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
        .set_dqblk      = dquot_set_dqblk
index 0ccd4ba3a2467f6783a396686b5ae20266ba515b..cf4edd87e854d140a76129dd30f519d3d3e1ce31 100644 (file)
@@ -2614,26 +2614,39 @@ out:
 EXPORT_SYMBOL(dquot_set_dqblk);
 
 /* Generic routine for getting common part of quota file information */
-int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_get_state(struct super_block *sb, struct qc_state *state)
 {
        struct mem_dqinfo *mi;
+       struct qc_type_state *tstate;
+       struct quota_info *dqopt = sb_dqopt(sb);
+       int type;
   
        mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
-               return -ESRCH;
+       memset(state, 0, sizeof(*state));
+       for (type = 0; type < MAXQUOTAS; type++) {
+               if (!sb_has_quota_active(sb, type))
+                       continue;
+               tstate = state->s_state + type;
+               mi = sb_dqopt(sb)->info + type;
+               tstate->flags = QCI_ACCT_ENABLED;
+               spin_lock(&dq_data_lock);
+               if (mi->dqi_flags & DQF_SYS_FILE)
+                       tstate->flags |= QCI_SYSFILE;
+               if (mi->dqi_flags & DQF_ROOT_SQUASH)
+                       tstate->flags |= QCI_ROOT_SQUASH;
+               if (sb_has_quota_limits_enabled(sb, type))
+                       tstate->flags |= QCI_LIMITS_ENFORCED;
+               tstate->spc_timelimit = mi->dqi_bgrace;
+               tstate->ino_timelimit = mi->dqi_igrace;
+               tstate->ino = dqopt->files[type]->i_ino;
+               tstate->blocks = dqopt->files[type]->i_blocks;
+               tstate->nextents = 1;   /* We don't know... */
+               spin_unlock(&dq_data_lock);
        }
-       mi = sb_dqopt(sb)->info + type;
-       spin_lock(&dq_data_lock);
-       ii->dqi_bgrace = mi->dqi_bgrace;
-       ii->dqi_igrace = mi->dqi_igrace;
-       ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK;
-       ii->dqi_valid = IIF_ALL;
-       spin_unlock(&dq_data_lock);
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
-EXPORT_SYMBOL(dquot_get_dqinfo);
+EXPORT_SYMBOL(dquot_get_state);
 
 /* Generic routine for setting common part of quota file information */
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
@@ -2677,7 +2690,7 @@ const struct quotactl_ops dquot_quotactl_ops = {
        .quota_on       = dquot_quota_on,
        .quota_off      = dquot_quota_off,
        .quota_sync     = dquot_quota_sync,
-       .get_info       = dquot_get_dqinfo,
+       .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
        .set_dqblk      = dquot_set_dqblk
@@ -2688,7 +2701,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = {
        .quota_enable   = dquot_quota_enable,
        .quota_disable  = dquot_quota_disable,
        .quota_sync     = dquot_quota_sync,
-       .get_info       = dquot_get_dqinfo,
+       .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
        .set_dqblk      = dquot_set_dqblk
index d14a799c77850e6a1dc8ca762244f325721785a7..00d50fca1005d6b5d8d60aaaa320586d7fd14994 100644 (file)
@@ -118,13 +118,30 @@ static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
 
 static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
 {
-       struct if_dqinfo info;
+       struct qc_state state;
+       struct qc_type_state *tstate;
+       struct if_dqinfo uinfo;
        int ret;
 
-       if (!sb->s_qcop->get_info)
+       /* This checks whether qc_state has enough entries... */
+       BUILD_BUG_ON(MAXQUOTAS > XQM_MAXQUOTAS);
+       if (!sb->s_qcop->get_state)
                return -ENOSYS;
-       ret = sb->s_qcop->get_info(sb, type, &info);
-       if (!ret && copy_to_user(addr, &info, sizeof(info)))
+       ret = sb->s_qcop->get_state(sb, &state);
+       if (ret)
+               return ret;
+       tstate = state.s_state + type;
+       if (!(tstate->flags & QCI_ACCT_ENABLED))
+               return -ESRCH;
+       memset(&uinfo, 0, sizeof(uinfo));
+       uinfo.dqi_bgrace = tstate->spc_timelimit;
+       uinfo.dqi_igrace = tstate->ino_timelimit;
+       if (tstate->flags & QCI_SYSFILE)
+               uinfo.dqi_flags |= DQF_SYS_FILE;
+       if (tstate->flags & QCI_ROOT_SQUASH)
+               uinfo.dqi_flags |= DQF_ROOT_SQUASH;
+       uinfo.dqi_valid = IIF_ALL;
+       if (!ret && copy_to_user(addr, &uinfo, sizeof(uinfo)))
                return -EFAULT;
        return ret;
 }
index 71fbbe3e2dab310481ef97ca12885a4a2137e8cf..68b5f182984e245c786f05cf29a6e148d2466654 100644 (file)
@@ -805,7 +805,7 @@ static const struct quotactl_ops reiserfs_qctl_operations = {
        .quota_on = reiserfs_quota_on,
        .quota_off = dquot_quota_off,
        .quota_sync = dquot_quota_sync,
-       .get_info = dquot_get_dqinfo,
+       .get_state = dquot_get_state,
        .set_info = dquot_set_dqinfo,
        .get_dqblk = dquot_get_dqblk,
        .set_dqblk = dquot_set_dqblk,
index d534e8ed308a1a116ae968ed78d98d9e183bb00a..6ecac0f3b2cadc5638f5016de42e00246f7ca194 100644 (file)
@@ -366,6 +366,37 @@ struct qc_dqblk {
 #define        QC_RT_SPACE     (1<<14)
 #define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE)
 
+#define QCI_SYSFILE            (1 << 0)        /* Quota file is hidden from userspace */
+#define QCI_ROOT_SQUASH                (1 << 1)        /* Root squash turned on */
+#define QCI_ACCT_ENABLED       (1 << 2)        /* Quota accounting enabled */
+#define QCI_LIMITS_ENFORCED    (1 << 3)        /* Quota limits enforced */
+
+/* Structures for communicating via ->get_state */
+struct qc_type_state {
+       unsigned int flags;             /* Flags QCI_* */
+       unsigned int spc_timelimit;     /* Time after which space softlimit is
+                                        * enforced */
+       unsigned int ino_timelimit;     /* Ditto for inode softlimit */
+       unsigned int rt_spc_timelimit;  /* Ditto for real-time space */
+       unsigned int spc_warnlimit;     /* Limit for number of space warnings */
+       unsigned int ino_warnlimit;     /* Ditto for inodes */
+       unsigned int rt_spc_warnlimit;  /* Ditto for real-time space */
+       unsigned long long ino;         /* Inode number of quota file */
+       blkcnt_t blocks;                /* Number of 512-byte blocks in the file */
+       blkcnt_t nextents;              /* Number of extents in the file */
+};
+
+struct qc_state {
+       unsigned int s_incoredqs;       /* Number of dquots in core */
+       /*
+        * Per quota type information. The array should really have
+        * max(MAXQUOTAS, XQM_MAXQUOTAS) entries. BUILD_BUG_ON in
+        * quota_getinfo() makes sure XQM_MAXQUOTAS is large enough.  Once VFS
+        * supports project quotas, this can be changed to MAXQUOTAS
+        */
+       struct qc_type_state s_state[XQM_MAXQUOTAS];
+};
+
 /* Operations handling requests from userspace */
 struct quotactl_ops {
        int (*quota_on)(struct super_block *, int, int, struct path *);
@@ -373,10 +404,10 @@ struct quotactl_ops {
        int (*quota_enable)(struct super_block *, unsigned int);
        int (*quota_disable)(struct super_block *, unsigned int);
        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 qc_dqblk *);
        int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);
+       int (*get_state)(struct super_block *, struct qc_state *);
        int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
        int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
        int (*rm_xquota)(struct super_block *, unsigned int);
index df73258cca47744ce4720659159ef4f4d96ec956..6509a29523e2caed286f5b0633eceb9571816ece 100644 (file)
@@ -95,7 +95,7 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
 int dquot_quota_off(struct super_block *sb, int type);
 int dquot_writeback_dquots(struct super_block *sb, int type);
 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_state(struct super_block *sb, struct qc_state *state);
 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 qc_dqblk *di);