/*
* Copyright (c) 2000-2003 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_alloc.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_trans_space.h"
#include "xfs_trans_priv.h"
#include "xfs_qm.h"
#include "xfs_trace.h"
/*
* Lock order:
*
* ip->i_lock
* qh->qh_lock
* qi->qi_dqlist_lock
* dquot->q_qlock (xfs_dqlock() and friends)
* dquot->q_flush (xfs_dqflock() and friends)
* xfs_Gqm->qm_dqfrlist_lock
*
* If two dquots need to be locked the order is user before group/project,
* otherwise by the lowest id first, see xfs_dqlock2.
*/
#ifdef DEBUG
xfs_buftarg_t *xfs_dqerror_target;
int xfs_do_dqerror;
int xfs_dqreq_num;
int xfs_dqerror_mod = 33;
#endif
static struct lock_class_key xfs_dquot_other_class;
/*
* This is called to free all the memory associated with a dquot
*/
void
xfs_qm_dqdestroy(
xfs_dquot_t *dqp)
{
ASSERT(list_empty(&dqp->q_freelist));
mutex_destroy(&dqp->q_qlock);
kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
atomic_dec(&xfs_Gqm->qm_totaldquots);
}
/*
* If default limits are in force, push them into the dquot now.
* We overwrite the dquot limits only if they are zero and this
* is not the root dquot.
*/
void
xfs_qm_adjust_dqlimits(
xfs_mount_t *mp,
xfs_disk_dquot_t *d)
{
xfs_quotainfo_t *q = mp->m_quotainfo;
ASSERT(d->d_id);
if (q->qi_bsoftlimit && !d->d_blk_softlimit)
d->d_blk_softlimit = cpu_to_be64(q->qi_bsoftlimit);
if (q->qi_bhardlimit && !d->d_blk_hardlimit)
d->d_blk_hardlimit = cpu_to_be64(q->qi_bhardlimit);
if (q->qi_isoftlimit && !d->d_ino_softlimit)
d->d_ino_softlimit = cpu_to_be64(q->qi_isoftlimit);
if (q->qi_ihardlimit && !d->d_ino_hardlimit)
d->d_ino_hardlimit = cpu_to_be64(q->qi_ihardlimit);
if (q->qi_rtbsoftlimit && !d->d_rtb_softlimit)
d->d_rtb_softlimit = cpu_to_be64(q->qi_rtbsoftlimit);
if (q->qi_rtbhardlimit && !d->d_rtb_hardlimit)
d->d_rtb_hardlimit = cpu_to_be64(q->qi_rtbhardlimit);
}
/*
* Check the limits and timers of a dquot and start or reset timers
* if necessary.
* This gets called even when quota enforcement is OFF, which makes our
* life a little less complicated. (We just don't reject any quota
* reservations in that case, when enforcement is off).
* We also return 0 as the values of the timers in Q_GETQUOTA calls, when
* enforcement's off.
* In contrast, warnings are a little different in that they don't
* 'automatically' get started when limits get exceeded. They do
* get reset to zero, however, when we find the count to be under
* the soft limit (they are only ever set non-zero via userspace).
*/
void
xfs_qm_adjust_dqtimers(
xfs_mount_t *mp,
xfs_disk_dquot_t *d)
{
ASSERT(d->d_id);
#ifdef DEBUG
if (d->d_blk_hardlimit)