linux/fs/xfs/xfs_quotaops.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008, Christoph Hellwig
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include "xfs.h"
  19#include "xfs_format.h"
  20#include "xfs_log_format.h"
  21#include "xfs_trans_resv.h"
  22#include "xfs_mount.h"
  23#include "xfs_inode.h"
  24#include "xfs_quota.h"
  25#include "xfs_trans.h"
  26#include "xfs_trace.h"
  27#include "xfs_icache.h"
  28#include "xfs_qm.h"
  29#include <linux/quota.h>
  30
  31
  32static void
  33xfs_qm_fill_state(
  34        struct qc_type_state    *tstate,
  35        struct xfs_mount        *mp,
  36        struct xfs_inode        *ip,
  37        xfs_ino_t               ino)
  38{
  39        struct xfs_quotainfo *q = mp->m_quotainfo;
  40        bool tempqip = false;
  41
  42        tstate->ino = ino;
  43        if (!ip && ino == NULLFSINO)
  44                return;
  45        if (!ip) {
  46                if (xfs_iget(mp, NULL, ino, 0, 0, &ip))
  47                        return;
  48                tempqip = true;
  49        }
  50        tstate->flags |= QCI_SYSFILE;
  51        tstate->blocks = ip->i_d.di_nblocks;
  52        tstate->nextents = ip->i_d.di_nextents;
  53        tstate->spc_timelimit = q->qi_btimelimit;
  54        tstate->ino_timelimit = q->qi_itimelimit;
  55        tstate->rt_spc_timelimit = q->qi_rtbtimelimit;
  56        tstate->spc_warnlimit = q->qi_bwarnlimit;
  57        tstate->ino_warnlimit = q->qi_iwarnlimit;
  58        tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
  59        if (tempqip)
  60                IRELE(ip);
  61}
  62
  63/*
  64 * Return quota status information, such as enforcements, quota file inode
  65 * numbers etc.
  66 */
  67static int
  68xfs_fs_get_quota_state(
  69        struct super_block      *sb,
  70        struct qc_state         *state)
  71{
  72        struct xfs_mount *mp = XFS_M(sb);
  73        struct xfs_quotainfo *q = mp->m_quotainfo;
  74
  75        memset(state, 0, sizeof(*state));
  76        if (!XFS_IS_QUOTA_RUNNING(mp))
  77                return 0;
  78        state->s_incoredqs = q->qi_dquots;
  79        if (XFS_IS_UQUOTA_RUNNING(mp))
  80                state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED;
  81        if (XFS_IS_UQUOTA_ENFORCED(mp))
  82                state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED;
  83        if (XFS_IS_GQUOTA_RUNNING(mp))
  84                state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED;
  85        if (XFS_IS_GQUOTA_ENFORCED(mp))
  86                state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED;
  87        if (XFS_IS_PQUOTA_RUNNING(mp))
  88                state->s_state[PRJQUOTA].flags |= QCI_ACCT_ENABLED;
  89        if (XFS_IS_PQUOTA_ENFORCED(mp))
  90                state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED;
  91
  92        xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip,
  93                          mp->m_sb.sb_uquotino);
  94        xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip,
  95                          mp->m_sb.sb_gquotino);
  96        xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip,
  97                          mp->m_sb.sb_pquotino);
  98        return 0;
  99}
 100
 101STATIC int
 102xfs_quota_type(int type)
 103{
 104        switch (type) {
 105        case USRQUOTA:
 106                return XFS_DQ_USER;
 107        case GRPQUOTA:
 108                return XFS_DQ_GROUP;
 109        default:
 110                return XFS_DQ_PROJ;
 111        }
 112}
 113
 114#define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK)
 115
 116/*
 117 * Adjust quota timers & warnings
 118 */
 119static int
 120xfs_fs_set_info(
 121        struct super_block      *sb,
 122        int                     type,
 123        struct qc_info          *info)
 124{
 125        struct xfs_mount *mp = XFS_M(sb);
 126        struct qc_dqblk newlim;
 127
 128        if (sb->s_flags & MS_RDONLY)
 129                return -EROFS;
 130        if (!XFS_IS_QUOTA_RUNNING(mp))
 131                return -ENOSYS;
 132        if (!XFS_IS_QUOTA_ON(mp))
 133                return -ESRCH;
 134        if (info->i_fieldmask & ~XFS_QC_SETINFO_MASK)
 135                return -EINVAL;
 136        if ((info->i_fieldmask & XFS_QC_SETINFO_MASK) == 0)
 137                return 0;
 138
 139        newlim.d_fieldmask = info->i_fieldmask;
 140        newlim.d_spc_timer = info->i_spc_timelimit;
 141        newlim.d_ino_timer = info->i_ino_timelimit;
 142        newlim.d_rt_spc_timer = info->i_rt_spc_timelimit;
 143        newlim.d_ino_warns = info->i_ino_warnlimit;
 144        newlim.d_spc_warns = info->i_spc_warnlimit;
 145        newlim.d_rt_spc_warns = info->i_rt_spc_warnlimit;
 146
 147        return xfs_qm_scall_setqlim(mp, 0, xfs_quota_type(type), &newlim);
 148}
 149
 150static unsigned int
 151xfs_quota_flags(unsigned int uflags)
 152{
 153        unsigned int flags = 0;
 154
 155        if (uflags & FS_QUOTA_UDQ_ACCT)
 156                flags |= XFS_UQUOTA_ACCT;
 157        if (uflags & FS_QUOTA_PDQ_ACCT)
 158                flags |= XFS_PQUOTA_ACCT;
 159        if (uflags & FS_QUOTA_GDQ_ACCT)
 160                flags |= XFS_GQUOTA_ACCT;
 161        if (uflags & FS_QUOTA_UDQ_ENFD)
 162                flags |= XFS_UQUOTA_ENFD;
 163        if (uflags & FS_QUOTA_GDQ_ENFD)
 164                flags |= XFS_GQUOTA_ENFD;
 165        if (uflags & FS_QUOTA_PDQ_ENFD)
 166                flags |= XFS_PQUOTA_ENFD;
 167
 168        return flags;
 169}
 170
 171STATIC int
 172xfs_quota_enable(
 173        struct super_block      *sb,
 174        unsigned int            uflags)
 175{
 176        struct xfs_mount        *mp = XFS_M(sb);
 177
 178        if (sb->s_flags & MS_RDONLY)
 179                return -EROFS;
 180        if (!XFS_IS_QUOTA_RUNNING(mp))
 181                return -ENOSYS;
 182
 183        return xfs_qm_scall_quotaon(mp, xfs_quota_flags(uflags));
 184}
 185
 186STATIC int
 187xfs_quota_disable(
 188        struct super_block      *sb,
 189        unsigned int            uflags)
 190{
 191        struct xfs_mount        *mp = XFS_M(sb);
 192
 193        if (sb->s_flags & MS_RDONLY)
 194                return -EROFS;
 195        if (!XFS_IS_QUOTA_RUNNING(mp))
 196                return -ENOSYS;
 197        if (!XFS_IS_QUOTA_ON(mp))
 198                return -EINVAL;
 199
 200        return xfs_qm_scall_quotaoff(mp, xfs_quota_flags(uflags));
 201}
 202
 203STATIC int
 204xfs_fs_rm_xquota(
 205        struct super_block      *sb,
 206        unsigned int            uflags)
 207{
 208        struct xfs_mount        *mp = XFS_M(sb);
 209        unsigned int            flags = 0;
 210
 211        if (sb->s_flags & MS_RDONLY)
 212                return -EROFS;
 213
 214        if (XFS_IS_QUOTA_ON(mp))
 215                return -EINVAL;
 216
 217        if (uflags & FS_USER_QUOTA)
 218                flags |= XFS_DQ_USER;
 219        if (uflags & FS_GROUP_QUOTA)
 220                flags |= XFS_DQ_GROUP;
 221        if (uflags & FS_PROJ_QUOTA)
 222                flags |= XFS_DQ_PROJ;
 223
 224        return xfs_qm_scall_trunc_qfiles(mp, flags);
 225}
 226
 227STATIC int
 228xfs_fs_get_dqblk(
 229        struct super_block      *sb,
 230        struct kqid             qid,
 231        struct qc_dqblk         *qdq)
 232{
 233        struct xfs_mount        *mp = XFS_M(sb);
 234        xfs_dqid_t              id;
 235
 236        if (!XFS_IS_QUOTA_RUNNING(mp))
 237                return -ENOSYS;
 238        if (!XFS_IS_QUOTA_ON(mp))
 239                return -ESRCH;
 240
 241        id = from_kqid(&init_user_ns, qid);
 242        return xfs_qm_scall_getquota(mp, &id,
 243                                      xfs_quota_type(qid.type), qdq, 0);
 244}
 245
 246/* Return quota info for active quota >= this qid */
 247STATIC int
 248xfs_fs_get_nextdqblk(
 249        struct super_block      *sb,
 250        struct kqid             *qid,
 251        struct qc_dqblk         *qdq)
 252{
 253        int                     ret;
 254        struct xfs_mount        *mp = XFS_M(sb);
 255        xfs_dqid_t              id;
 256
 257        if (!XFS_IS_QUOTA_RUNNING(mp))
 258                return -ENOSYS;
 259        if (!XFS_IS_QUOTA_ON(mp))
 260                return -ESRCH;
 261
 262        id = from_kqid(&init_user_ns, *qid);
 263        ret = xfs_qm_scall_getquota(mp, &id,
 264                                    xfs_quota_type(qid->type), qdq,
 265                                    XFS_QMOPT_DQNEXT);
 266        if (ret)
 267                return ret;
 268
 269        /* ID may be different, so convert back what we got */
 270        *qid = make_kqid(current_user_ns(), qid->type, id);
 271        return 0;
 272        
 273}
 274
 275STATIC int
 276xfs_fs_set_dqblk(
 277        struct super_block      *sb,
 278        struct kqid             qid,
 279        struct qc_dqblk         *qdq)
 280{
 281        struct xfs_mount        *mp = XFS_M(sb);
 282
 283        if (sb->s_flags & MS_RDONLY)
 284                return -EROFS;
 285        if (!XFS_IS_QUOTA_RUNNING(mp))
 286                return -ENOSYS;
 287        if (!XFS_IS_QUOTA_ON(mp))
 288                return -ESRCH;
 289
 290        return xfs_qm_scall_setqlim(mp, from_kqid(&init_user_ns, qid),
 291                                     xfs_quota_type(qid.type), qdq);
 292}
 293
 294const struct quotactl_ops xfs_quotactl_operations = {
 295        .get_state              = xfs_fs_get_quota_state,
 296        .set_info               = xfs_fs_set_info,
 297        .quota_enable           = xfs_quota_enable,
 298        .quota_disable          = xfs_quota_disable,
 299        .rm_xquota              = xfs_fs_rm_xquota,
 300        .get_dqblk              = xfs_fs_get_dqblk,
 301        .get_nextdqblk          = xfs_fs_get_nextdqblk,
 302        .set_dqblk              = xfs_fs_set_dqblk,
 303};
 304