linux/fs/xfs/xfs_qm_bhv.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
   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_fs.h"
  20#include "xfs_format.h"
  21#include "xfs_log_format.h"
  22#include "xfs_trans_resv.h"
  23#include "xfs_quota.h"
  24#include "xfs_mount.h"
  25#include "xfs_inode.h"
  26#include "xfs_error.h"
  27#include "xfs_trans.h"
  28#include "xfs_qm.h"
  29
  30
  31STATIC void
  32xfs_fill_statvfs_from_dquot(
  33        struct kstatfs          *statp,
  34        struct xfs_dquot        *dqp)
  35{
  36        __uint64_t              limit;
  37
  38        limit = dqp->q_core.d_blk_softlimit ?
  39                be64_to_cpu(dqp->q_core.d_blk_softlimit) :
  40                be64_to_cpu(dqp->q_core.d_blk_hardlimit);
  41        if (limit && statp->f_blocks > limit) {
  42                statp->f_blocks = limit;
  43                statp->f_bfree = statp->f_bavail =
  44                        (statp->f_blocks > dqp->q_res_bcount) ?
  45                         (statp->f_blocks - dqp->q_res_bcount) : 0;
  46        }
  47
  48        limit = dqp->q_core.d_ino_softlimit ?
  49                be64_to_cpu(dqp->q_core.d_ino_softlimit) :
  50                be64_to_cpu(dqp->q_core.d_ino_hardlimit);
  51        if (limit && statp->f_files > limit) {
  52                statp->f_files = limit;
  53                statp->f_ffree =
  54                        (statp->f_files > dqp->q_res_icount) ?
  55                         (statp->f_ffree - dqp->q_res_icount) : 0;
  56        }
  57}
  58
  59
  60/*
  61 * Directory tree accounting is implemented using project quotas, where
  62 * the project identifier is inherited from parent directories.
  63 * A statvfs (df, etc.) of a directory that is using project quota should
  64 * return a statvfs of the project, not the entire filesystem.
  65 * This makes such trees appear as if they are filesystems in themselves.
  66 */
  67void
  68xfs_qm_statvfs(
  69        xfs_inode_t             *ip,
  70        struct kstatfs          *statp)
  71{
  72        xfs_mount_t             *mp = ip->i_mount;
  73        xfs_dquot_t             *dqp;
  74
  75        if (!xfs_qm_dqget(mp, NULL, xfs_get_projid(ip), XFS_DQ_PROJ, 0, &dqp)) {
  76                xfs_fill_statvfs_from_dquot(statp, dqp);
  77                xfs_qm_dqput(dqp);
  78        }
  79}
  80
  81int
  82xfs_qm_newmount(
  83        xfs_mount_t     *mp,
  84        uint            *needquotamount,
  85        uint            *quotaflags)
  86{
  87        uint            quotaondisk;
  88        uint            uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0;
  89
  90        quotaondisk = xfs_sb_version_hasquota(&mp->m_sb) &&
  91                                (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT);
  92
  93        if (quotaondisk) {
  94                uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
  95                pquotaondisk = mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT;
  96                gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
  97        }
  98
  99        /*
 100         * If the device itself is read-only, we can't allow
 101         * the user to change the state of quota on the mount -
 102         * this would generate a transaction on the ro device,
 103         * which would lead to an I/O error and shutdown
 104         */
 105
 106        if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
 107            (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
 108             (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
 109            (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)) ||
 110             (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
 111            (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)))  &&
 112            xfs_dev_is_read_only(mp, "changing quota state")) {
 113                xfs_warn(mp, "please mount with%s%s%s%s.",
 114                        (!quotaondisk ? "out quota" : ""),
 115                        (uquotaondisk ? " usrquota" : ""),
 116                        (gquotaondisk ? " grpquota" : ""),
 117                        (pquotaondisk ? " prjquota" : ""));
 118                return -EPERM;
 119        }
 120
 121        if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
 122                /*
 123                 * Call mount_quotas at this point only if we won't have to do
 124                 * a quotacheck.
 125                 */
 126                if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
 127                        /*
 128                         * If an error occurred, qm_mount_quotas code
 129                         * has already disabled quotas. So, just finish
 130                         * mounting, and get on with the boring life
 131                         * without disk quotas.
 132                         */
 133                        xfs_qm_mount_quotas(mp);
 134                } else {
 135                        /*
 136                         * Clear the quota flags, but remember them. This
 137                         * is so that the quota code doesn't get invoked
 138                         * before we're ready. This can happen when an
 139                         * inode goes inactive and wants to free blocks,
 140                         * or via xfs_log_mount_finish.
 141                         */
 142                        *needquotamount = true;
 143                        *quotaflags = mp->m_qflags;
 144                        mp->m_qflags = 0;
 145                }
 146        }
 147
 148        return 0;
 149}
 150