xfs
[Top] [All Lists]

[PATCH 10/16] quota: Wire up Q_GETXSTATE and Q_GETXSTATV calls to work w

To: linux-fsdevel@xxxxxxxxxxxxxxx
Subject: [PATCH 10/16] quota: Wire up Q_GETXSTATE and Q_GETXSTATV calls to work with ->get_state
From: Jan Kara <jack@xxxxxxx>
Date: Mon, 26 Jan 2015 15:34:27 +0100
Cc: xfs@xxxxxxxxxxx, cluster-devel@xxxxxxxxxx, ocfs2-devel@xxxxxxxxxxxxxx, Jan Kara <jack@xxxxxxx>
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1422282873-3381-1-git-send-email-jack@xxxxxxx>
References: <1422282873-3381-1-git-send-email-jack@xxxxxxx>
Add appropriate conversion functions so that filesystems supporting
->get_state() method can be queried using Q_GETXSTATE and Q_GETXSTATV
calls.

Reviewed-by: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: Jan Kara <jack@xxxxxxx>
---
 fs/quota/quota.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 134 insertions(+), 4 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 00d50fca1005..83939ff4c444 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -269,25 +269,152 @@ static int quota_disable(struct super_block *sb, void 
__user *addr)
        return sb->s_qcop->quota_disable(sb, flags);
 }
 
+static int quota_state_to_flags(struct qc_state *state)
+{
+       int flags = 0;
+
+       if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED)
+               flags |= FS_QUOTA_UDQ_ACCT;
+       if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED)
+               flags |= FS_QUOTA_UDQ_ENFD;
+       if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)
+               flags |= FS_QUOTA_GDQ_ACCT;
+       if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED)
+               flags |= FS_QUOTA_GDQ_ENFD;
+       if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED)
+               flags |= FS_QUOTA_PDQ_ACCT;
+       if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED)
+               flags |= FS_QUOTA_PDQ_ENFD;
+       return flags;
+}
+
+static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs)
+{
+       int type;
+       struct qc_state state;
+       int ret;
+
+       ret = sb->s_qcop->get_state(sb, &state);
+       if (ret < 0)
+               return ret;
+
+       memset(fqs, 0, sizeof(*fqs));
+       fqs->qs_version = FS_QSTAT_VERSION;
+       fqs->qs_flags = quota_state_to_flags(&state);
+       /* No quota enabled? */
+       if (!fqs->qs_flags)
+               return -ENOSYS;
+       fqs->qs_incoredqs = state.s_incoredqs;
+       /*
+        * GETXSTATE quotactl has space for just one set of time limits so
+        * report them for the first enabled quota type
+        */
+       for (type = 0; type < XQM_MAXQUOTAS; type++)
+               if (state.s_state[type].flags & QCI_ACCT_ENABLED)
+                       break;
+       BUG_ON(type == XQM_MAXQUOTAS);
+       fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
+       fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
+       fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
+       fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
+       fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
+       if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) {
+               fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
+               fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
+               fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
+       }
+       if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) {
+               fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
+               fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
+               fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
+       }
+       if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) {
+               /*
+                * Q_XGETQSTAT doesn't have room for both group and project
+                * quotas.  So, allow the project quota values to be copied out
+                * only if there is no group quota information available.
+                */
+               if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) {
+                       fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino;
+                       fqs->qs_gquota.qfs_nblks =
+                                       state.s_state[PRJQUOTA].blocks;
+                       fqs->qs_gquota.qfs_nextents =
+                                       state.s_state[PRJQUOTA].nextents;
+               }
+       }
+       return 0;
+}
+
 static int quota_getxstate(struct super_block *sb, void __user *addr)
 {
        struct fs_quota_stat fqs;
        int ret;
 
-       if (!sb->s_qcop->get_xstate)
+       if (!sb->s_qcop->get_xstate && !sb->s_qcop->get_state)
                return -ENOSYS;
-       ret = sb->s_qcop->get_xstate(sb, &fqs);
+       if (sb->s_qcop->get_state)
+               ret = quota_getstate(sb, &fqs);
+       else
+               ret = sb->s_qcop->get_xstate(sb, &fqs);
        if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
                return -EFAULT;
        return ret;
 }
 
+static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs)
+{
+       int type;
+       struct qc_state state;
+       int ret;
+
+       ret = sb->s_qcop->get_state(sb, &state);
+       if (ret < 0)
+               return ret;
+
+       memset(fqs, 0, sizeof(*fqs));
+       fqs->qs_version = FS_QSTAT_VERSION;
+       fqs->qs_flags = quota_state_to_flags(&state);
+       /* No quota enabled? */
+       if (!fqs->qs_flags)
+               return -ENOSYS;
+       fqs->qs_incoredqs = state.s_incoredqs;
+       /*
+        * GETXSTATV quotactl has space for just one set of time limits so
+        * report them for the first enabled quota type
+        */
+       for (type = 0; type < XQM_MAXQUOTAS; type++)
+               if (state.s_state[type].flags & QCI_ACCT_ENABLED)
+                       break;
+       BUG_ON(type == XQM_MAXQUOTAS);
+       fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
+       fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
+       fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
+       fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
+       fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
+       if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) {
+               fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
+               fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
+               fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
+       }
+       if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) {
+               fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
+               fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
+               fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
+       }
+       if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) {
+               fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino;
+               fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks;
+               fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents;
+       }
+       return 0;
+}
+
 static int quota_getxstatev(struct super_block *sb, void __user *addr)
 {
        struct fs_quota_statv fqs;
        int ret;
 
-       if (!sb->s_qcop->get_xstatev)
+       if (!sb->s_qcop->get_xstatev && !sb->s_qcop->get_state)
                return -ENOSYS;
 
        memset(&fqs, 0, sizeof(fqs));
@@ -301,7 +428,10 @@ static int quota_getxstatev(struct super_block *sb, void 
__user *addr)
        default:
                return -EINVAL;
        }
-       ret = sb->s_qcop->get_xstatev(sb, &fqs);
+       if (sb->s_qcop->get_state)
+               ret = quota_getstatev(sb, &fqs);
+       else
+               ret = sb->s_qcop->get_xstatev(sb, &fqs);
        if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
                return -EFAULT;
        return ret;
-- 
2.1.2

<Prev in Thread] Current Thread [Next in Thread>