Exemplo n.º 1
0
/*
 * Turn off quota accounting and/or enforcement for all udquots and/or
 * gdquots. Called only at unmount time.
 *
 * This assumes that there are no dquots of this file system cached
 * incore, and modifies the ondisk dquot directly. Therefore, for example,
 * it is an error to call this twice, without purging the cache.
 */
STATIC int
xfs_qm_scall_quotaoff(
	xfs_mount_t		*mp,
	uint			flags,
	boolean_t		force)
{
	uint			dqtype;
	unsigned long	s;
	int			error;
	uint			inactivate_flags;
	xfs_qoff_logitem_t	*qoffstart;
	int			nculprits;

	if (!force && !capable(CAP_SYS_ADMIN))
		return XFS_ERROR(EPERM);
	/*
	 * No file system can have quotas enabled on disk but not in core.
	 * Note that quota utilities (like quotaoff) _expect_
	 * errno == EEXIST here.
	 */
	if ((mp->m_qflags & flags) == 0)
		return XFS_ERROR(EEXIST);
	error = 0;

	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);

	/*
	 * We don't want to deal with two quotaoffs messing up each other,
	 * so we're going to serialize it. quotaoff isn't exactly a performance
	 * critical thing.
	 * If quotaoff, then we must be dealing with the root filesystem.
	 */
	ASSERT(mp->m_quotainfo);
	if (mp->m_quotainfo)
		mutex_lock(&(XFS_QI_QOFFLOCK(mp)));

	ASSERT(mp->m_quotainfo);

	/*
	 * If we're just turning off quota enforcement, change mp and go.
	 */
	if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
		mp->m_qflags &= ~(flags);

		s = XFS_SB_LOCK(mp);
		mp->m_sb.sb_qflags = mp->m_qflags;
		XFS_SB_UNLOCK(mp, s);
		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));

		/* XXX what to do if error ? Revert back to old vals incore ? */
		error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
		return (error);
	}

	dqtype = 0;
	inactivate_flags = 0;
	/*
	 * If accounting is off, we must turn enforcement off, clear the
	 * quota 'CHKD' certificate to make it known that we have to
	 * do a quotacheck the next time this quota is turned on.
	 */
	if (flags & XFS_UQUOTA_ACCT) {
		dqtype |= XFS_QMOPT_UQUOTA;
		flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
		inactivate_flags |= XFS_UQUOTA_ACTIVE;
	}
	if (flags & XFS_GQUOTA_ACCT) {
		dqtype |= XFS_QMOPT_GQUOTA;
		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
		inactivate_flags |= XFS_GQUOTA_ACTIVE;
	} else if (flags & XFS_PQUOTA_ACCT) {
		dqtype |= XFS_QMOPT_PQUOTA;
		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
		inactivate_flags |= XFS_PQUOTA_ACTIVE;
	}

	/*
	 * Nothing to do?  Don't complain. This happens when we're just
	 * turning off quota enforcement.
	 */
	if ((mp->m_qflags & flags) == 0) {
		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
		return (0);
	}

	/*
	 * Write the LI_QUOTAOFF log record, and do SB changes atomically,
	 * and synchronously.
	 */
	xfs_qm_log_quotaoff(mp, &qoffstart, flags);

	/*
	 * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
	 * to take care of the race between dqget and quotaoff. We don't take
	 * any special locks to reset these bits. All processes need to check
	 * these bits *after* taking inode lock(s) to see if the particular
	 * quota type is in the process of being turned off. If *ACTIVE, it is
	 * guaranteed that all dquot structures and all quotainode ptrs will all
	 * stay valid as long as that inode is kept locked.
	 *
	 * There is no turning back after this.
	 */
	mp->m_qflags &= ~inactivate_flags;

	/*
	 * Give back all the dquot reference(s) held by inodes.
	 * Here we go thru every single incore inode in this file system, and
	 * do a dqrele on the i_udquot/i_gdquot that it may have.
	 * Essentially, as long as somebody has an inode locked, this guarantees
	 * that quotas will not be turned off. This is handy because in a
	 * transaction once we lock the inode(s) and check for quotaon, we can
	 * depend on the quota inodes (and other things) being valid as long as
	 * we keep the lock(s).
	 */
	xfs_qm_dqrele_all_inodes(mp, flags);

	/*
	 * Next we make the changes in the quota flag in the mount struct.
	 * This isn't protected by a particular lock directly, because we
	 * don't want to take a mrlock everytime we depend on quotas being on.
	 */
	mp->m_qflags &= ~(flags);

	/*
	 * Go through all the dquots of this file system and purge them,
	 * according to what was turned off. We may not be able to get rid
	 * of all dquots, because dquots can have temporary references that
	 * are not attached to inodes. eg. xfs_setattr, xfs_create.
	 * So, if we couldn't purge all the dquots from the filesystem,
	 * we can't get rid of the incore data structures.
	 */
	while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF)))
		delay(10 * nculprits);

	/*
	 * Transactions that had started before ACTIVE state bit was cleared
	 * could have logged many dquots, so they'd have higher LSNs than
	 * the first QUOTAOFF log record does. If we happen to crash when
	 * the tail of the log has gone past the QUOTAOFF record, but
	 * before the last dquot modification, those dquots __will__
	 * recover, and that's not good.
	 *
	 * So, we have QUOTAOFF start and end logitems; the start
	 * logitem won't get overwritten until the end logitem appears...
	 */
	xfs_qm_log_quotaoff_end(mp, qoffstart, flags);

	/*
	 * If quotas is completely disabled, close shop.
	 */
	if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
	    ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
		xfs_qm_destroy_quotainfo(mp);
		return (0);
	}

	/*
	 * Release our quotainode references, and vn_purge them,
	 * if we don't need them anymore.
	 */
	if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
		XFS_PURGE_INODE(XFS_QI_UQIP(mp));
		XFS_QI_UQIP(mp) = NULL;
	}
	if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) {
		XFS_PURGE_INODE(XFS_QI_GQIP(mp));
		XFS_QI_GQIP(mp) = NULL;
	}
	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));

	return (error);
}
Exemplo n.º 2
0
/*
 * Switch on (a given) quota enforcement for a filesystem.  This takes
 * effect immediately.
 * (Switching on quota accounting must be done at mount time.)
 */
STATIC int
xfs_qm_scall_quotaon(
	xfs_mount_t	*mp,
	uint		flags)
{
	int		error;
	unsigned long	s;
	uint		qf;
	uint		accflags;
	__int64_t	sbflags;

	if (!capable(CAP_SYS_ADMIN))
		return XFS_ERROR(EPERM);

	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
	/*
	 * Switching on quota accounting must be done at mount time.
	 */
	accflags = flags & XFS_ALL_QUOTA_ACCT;
	flags &= ~(XFS_ALL_QUOTA_ACCT);

	sbflags = 0;

	if (flags == 0) {
		qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
		return XFS_ERROR(EINVAL);
	}

	/* No fs can turn on quotas with a delayed effect */
	ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);

	/*
	 * Can't enforce without accounting. We check the superblock
	 * qflags here instead of m_qflags because rootfs can have
	 * quota acct on ondisk without m_qflags' knowing.
	 */
	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
	    (flags & XFS_UQUOTA_ENFD))
	    ||
	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
	    (flags & XFS_OQUOTA_ENFD))
	    ||
	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
	    (flags & XFS_OQUOTA_ENFD))) {
		qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
			flags, mp->m_sb.sb_qflags);
		return XFS_ERROR(EINVAL);
	}
	/*
	 * If everything's upto-date incore, then don't waste time.
	 */
	if ((mp->m_qflags & flags) == flags)
		return XFS_ERROR(EEXIST);

	/*
	 * Change sb_qflags on disk but not incore mp->qflags
	 * if this is the root filesystem.
	 */
	s = XFS_SB_LOCK(mp);
	qf = mp->m_sb.sb_qflags;
	mp->m_sb.sb_qflags = qf | flags;
	XFS_SB_UNLOCK(mp, s);

	/*
	 * There's nothing to change if it's the same.
	 */
	if ((qf & flags) == flags && sbflags == 0)
		return XFS_ERROR(EEXIST);
	sbflags |= XFS_SB_QFLAGS;

	if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
		return (error);
	/*
	 * If we aren't trying to switch on quota enforcement, we are done.
	 */
	if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
	     (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
	     ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
	     (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
	     ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
	     (mp->m_qflags & XFS_GQUOTA_ACCT)) ||
	    (flags & XFS_ALL_QUOTA_ENFD) == 0)
		return (0);

	if (! XFS_IS_QUOTA_RUNNING(mp))
		return XFS_ERROR(ESRCH);

	/*
	 * Switch on quota enforcement in core.
	 */
	mutex_lock(&(XFS_QI_QOFFLOCK(mp)));
	mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));

	return (0);
}
Exemplo n.º 3
0
/*
 * This is called from xfs_mountfs to start quotas and initialize all
 * necessary data structures like quotainfo.  This is also responsible for
 * running a quotacheck as necessary.  We are guaranteed that the superblock
 * is consistently read in at this point.
 *
 * If we fail here, the mount will continue with quota turned off. We don't
 * need to inidicate success or failure at all.
 */
void
xfs_qm_mount_quotas(
	xfs_mount_t	*mp)
{
	int		error = 0;
	uint		sbf;

	/*
	 * If quotas on realtime volumes is not supported, we disable
	 * quotas immediately.
	 */
	if (mp->m_sb.sb_rextents) {
		xfs_notice(mp, "Cannot turn on quotas for realtime filesystem");
		mp->m_qflags = 0;
		goto write_changes;
	}

	ASSERT(XFS_IS_QUOTA_RUNNING(mp));

	/*
	 * Allocate the quotainfo structure inside the mount struct, and
	 * create quotainode(s), and change/rev superblock if necessary.
	 */
	error = xfs_qm_init_quotainfo(mp);
	if (error) {
		/*
		 * We must turn off quotas.
		 */
		ASSERT(mp->m_quotainfo == NULL);
		mp->m_qflags = 0;
		goto write_changes;
	}
	/*
	 * If any of the quotas are not consistent, do a quotacheck.
	 */
	if (XFS_QM_NEED_QUOTACHECK(mp)) {
		error = xfs_qm_quotacheck(mp);
		if (error) {
			/* Quotacheck failed and disabled quotas. */
			return;
		}
	}
	/* 
	 * If one type of quotas is off, then it will lose its
	 * quotachecked status, since we won't be doing accounting for
	 * that type anymore.
	 */
	if (!XFS_IS_UQUOTA_ON(mp))
		mp->m_qflags &= ~XFS_UQUOTA_CHKD;
	if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp)))
		mp->m_qflags &= ~XFS_OQUOTA_CHKD;

 write_changes:
	/*
	 * We actually don't have to acquire the m_sb_lock at all.
	 * This can only be called from mount, and that's single threaded. XXX
	 */
	spin_lock(&mp->m_sb_lock);
	sbf = mp->m_sb.sb_qflags;
	mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
	spin_unlock(&mp->m_sb_lock);

	if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
		if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
			/*
			 * We could only have been turning quotas off.
			 * We aren't in very good shape actually because
			 * the incore structures are convinced that quotas are
			 * off, but the on disk superblock doesn't know that !
			 */
			ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
			xfs_alert(mp, "%s: Superblock update failed!",
				__func__);
		}
	}

	if (error) {
		xfs_warn(mp, "Failed to initialize disk quotas.");
		return;
	}
}
/*
 * Turn off quota accounting and/or enforcement for all udquots and/or
 * gdquots. Called only at unmount time.
 *
 * This assumes that there are no dquots of this file system cached
 * incore, and modifies the ondisk dquot directly. Therefore, for example,
 * it is an error to call this twice, without purging the cache.
 */
int
xfs_qm_scall_quotaoff(
    xfs_mount_t		*mp,
    uint			flags)
{
    struct xfs_quotainfo	*q = mp->m_quotainfo;
    uint			dqtype;
    int			error;
    uint			inactivate_flags;
    xfs_qoff_logitem_t	*qoffstart;

    /*
     * No file system can have quotas enabled on disk but not in core.
     * Note that quota utilities (like quotaoff) _expect_
     * errno == EEXIST here.
     */
    if ((mp->m_qflags & flags) == 0)
        return XFS_ERROR(EEXIST);
    error = 0;

    flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);

    /*
     * We don't want to deal with two quotaoffs messing up each other,
     * so we're going to serialize it. quotaoff isn't exactly a performance
     * critical thing.
     * If quotaoff, then we must be dealing with the root filesystem.
     */
    ASSERT(q);
    mutex_lock(&q->qi_quotaofflock);

    /*
     * If we're just turning off quota enforcement, change mp and go.
     */
    if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
        mp->m_qflags &= ~(flags);

        spin_lock(&mp->m_sb_lock);
        mp->m_sb.sb_qflags = mp->m_qflags;
        spin_unlock(&mp->m_sb_lock);
        mutex_unlock(&q->qi_quotaofflock);

        /* XXX what to do if error ? Revert back to old vals incore ? */
        error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
        return (error);
    }

    dqtype = 0;
    inactivate_flags = 0;
    /*
     * If accounting is off, we must turn enforcement off, clear the
     * quota 'CHKD' certificate to make it known that we have to
     * do a quotacheck the next time this quota is turned on.
     */
    if (flags & XFS_UQUOTA_ACCT) {
        dqtype |= XFS_QMOPT_UQUOTA;
        flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
        inactivate_flags |= XFS_UQUOTA_ACTIVE;
    }
    if (flags & XFS_GQUOTA_ACCT) {
        dqtype |= XFS_QMOPT_GQUOTA;
        flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
        inactivate_flags |= XFS_GQUOTA_ACTIVE;
    }
    if (flags & XFS_PQUOTA_ACCT) {
        dqtype |= XFS_QMOPT_PQUOTA;
        flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
        inactivate_flags |= XFS_PQUOTA_ACTIVE;
    }

    /*
     * Nothing to do?  Don't complain. This happens when we're just
     * turning off quota enforcement.
     */
    if ((mp->m_qflags & flags) == 0)
        goto out_unlock;

    /*
     * Write the LI_QUOTAOFF log record, and do SB changes atomically,
     * and synchronously. If we fail to write, we should abort the
     * operation as it cannot be recovered safely if we crash.
     */
    error = xfs_qm_log_quotaoff(mp, &qoffstart, flags);
    if (error)
        goto out_unlock;

    /*
     * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
     * to take care of the race between dqget and quotaoff. We don't take
     * any special locks to reset these bits. All processes need to check
     * these bits *after* taking inode lock(s) to see if the particular
     * quota type is in the process of being turned off. If *ACTIVE, it is
     * guaranteed that all dquot structures and all quotainode ptrs will all
     * stay valid as long as that inode is kept locked.
     *
     * There is no turning back after this.
     */
    mp->m_qflags &= ~inactivate_flags;

    /*
     * Give back all the dquot reference(s) held by inodes.
     * Here we go thru every single incore inode in this file system, and
     * do a dqrele on the i_udquot/i_gdquot that it may have.
     * Essentially, as long as somebody has an inode locked, this guarantees
     * that quotas will not be turned off. This is handy because in a
     * transaction once we lock the inode(s) and check for quotaon, we can
     * depend on the quota inodes (and other things) being valid as long as
     * we keep the lock(s).
     */
    xfs_qm_dqrele_all_inodes(mp, flags);

    /*
     * Next we make the changes in the quota flag in the mount struct.
     * This isn't protected by a particular lock directly, because we
     * don't want to take a mrlock every time we depend on quotas being on.
     */
    mp->m_qflags &= ~flags;

    /*
     * Go through all the dquots of this file system and purge them,
     * according to what was turned off.
     */
    xfs_qm_dqpurge_all(mp, dqtype);

    /*
     * Transactions that had started before ACTIVE state bit was cleared
     * could have logged many dquots, so they'd have higher LSNs than
     * the first QUOTAOFF log record does. If we happen to crash when
     * the tail of the log has gone past the QUOTAOFF record, but
     * before the last dquot modification, those dquots __will__
     * recover, and that's not good.
     *
     * So, we have QUOTAOFF start and end logitems; the start
     * logitem won't get overwritten until the end logitem appears...
     */
    error = xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
    if (error) {
        /* We're screwed now. Shutdown is the only option. */
        xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
        goto out_unlock;
    }

    /*
     * If all quotas are completely turned off, close shop.
     */
    if (mp->m_qflags == 0) {
        mutex_unlock(&q->qi_quotaofflock);
        xfs_qm_destroy_quotainfo(mp);
        return (0);
    }

    /*
     * Release our quotainode references if we don't need them anymore.
     */
    if ((dqtype & XFS_QMOPT_UQUOTA) && q->qi_uquotaip) {
        IRELE(q->qi_uquotaip);
        q->qi_uquotaip = NULL;
    }
    if ((dqtype & XFS_QMOPT_GQUOTA) && q->qi_gquotaip) {
        IRELE(q->qi_gquotaip);
        q->qi_gquotaip = NULL;
    }
    if ((dqtype & XFS_QMOPT_PQUOTA) && q->qi_pquotaip) {
        IRELE(q->qi_pquotaip);
        q->qi_pquotaip = NULL;
    }

out_unlock:
    mutex_unlock(&q->qi_quotaofflock);
    return error;
}
/*
 * Switch on (a given) quota enforcement for a filesystem.  This takes
 * effect immediately.
 * (Switching on quota accounting must be done at mount time.)
 */
int
xfs_qm_scall_quotaon(
    xfs_mount_t	*mp,
    uint		flags)
{
    int		error;
    uint		qf;
    __int64_t	sbflags;

    flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
    /*
     * Switching on quota accounting must be done at mount time.
     */
    flags &= ~(XFS_ALL_QUOTA_ACCT);

    sbflags = 0;

    if (flags == 0) {
        xfs_debug(mp, "%s: zero flags, m_qflags=%x",
                  __func__, mp->m_qflags);
        return XFS_ERROR(EINVAL);
    }

    /* No fs can turn on quotas with a delayed effect */
    ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);

    /*
     * Can't enforce without accounting. We check the superblock
     * qflags here instead of m_qflags because rootfs can have
     * quota acct on ondisk without m_qflags' knowing.
     */
    if (((flags & XFS_UQUOTA_ACCT) == 0 &&
            (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
            (flags & XFS_UQUOTA_ENFD)) ||
            ((flags & XFS_GQUOTA_ACCT) == 0 &&
             (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
             (flags & XFS_GQUOTA_ENFD)) ||
            ((flags & XFS_PQUOTA_ACCT) == 0 &&
             (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
             (flags & XFS_PQUOTA_ENFD))) {
        xfs_debug(mp,
                  "%s: Can't enforce without acct, flags=%x sbflags=%x",
                  __func__, flags, mp->m_sb.sb_qflags);
        return XFS_ERROR(EINVAL);
    }
    /*
     * If everything's up to-date incore, then don't waste time.
     */
    if ((mp->m_qflags & flags) == flags)
        return XFS_ERROR(EEXIST);

    /*
     * Change sb_qflags on disk but not incore mp->qflags
     * if this is the root filesystem.
     */
    spin_lock(&mp->m_sb_lock);
    qf = mp->m_sb.sb_qflags;
    mp->m_sb.sb_qflags = qf | flags;
    spin_unlock(&mp->m_sb_lock);

    /*
     * There's nothing to change if it's the same.
     */
    if ((qf & flags) == flags && sbflags == 0)
        return XFS_ERROR(EEXIST);
    sbflags |= XFS_SB_QFLAGS;

    if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
        return (error);
    /*
     * If we aren't trying to switch on quota enforcement, we are done.
     */
    if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
            (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
            ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
             (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
            ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
             (mp->m_qflags & XFS_GQUOTA_ACCT)) ||
            (flags & XFS_ALL_QUOTA_ENFD) == 0)
        return (0);

    if (! XFS_IS_QUOTA_RUNNING(mp))
        return XFS_ERROR(ESRCH);

    /*
     * Switch on quota enforcement in core.
     */
    mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
    mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
    mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);

    return (0);
}
int
xfs_qm_scall_quotaoff(
	xfs_mount_t		*mp,
	uint			flags)
{
	struct xfs_quotainfo	*q = mp->m_quotainfo;
	uint			dqtype;
	int			error;
	uint			inactivate_flags;
	xfs_qoff_logitem_t	*qoffstart;

	if ((mp->m_qflags & flags) == 0)
		return XFS_ERROR(EEXIST);
	error = 0;

	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);

	ASSERT(q);
	mutex_lock(&q->qi_quotaofflock);

	if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
		mp->m_qflags &= ~(flags);

		spin_lock(&mp->m_sb_lock);
		mp->m_sb.sb_qflags = mp->m_qflags;
		spin_unlock(&mp->m_sb_lock);
		mutex_unlock(&q->qi_quotaofflock);

		
		error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
		return (error);
	}

	dqtype = 0;
	inactivate_flags = 0;
	if (flags & XFS_UQUOTA_ACCT) {
		dqtype |= XFS_QMOPT_UQUOTA;
		flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
		inactivate_flags |= XFS_UQUOTA_ACTIVE;
	}
	if (flags & XFS_GQUOTA_ACCT) {
		dqtype |= XFS_QMOPT_GQUOTA;
		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
		inactivate_flags |= XFS_GQUOTA_ACTIVE;
	} else if (flags & XFS_PQUOTA_ACCT) {
		dqtype |= XFS_QMOPT_PQUOTA;
		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
		inactivate_flags |= XFS_PQUOTA_ACTIVE;
	}

	if ((mp->m_qflags & flags) == 0)
		goto out_unlock;

	error = xfs_qm_log_quotaoff(mp, &qoffstart, flags);
	if (error)
		goto out_unlock;

	mp->m_qflags &= ~inactivate_flags;

	xfs_qm_dqrele_all_inodes(mp, flags);

	mp->m_qflags &= ~flags;

	xfs_qm_dqpurge_all(mp, dqtype);

	/*
	 * Transactions that had started before ACTIVE state bit was cleared
	 * could have logged many dquots, so they'd have higher LSNs than
	 * the first QUOTAOFF log record does. If we happen to crash when
	 * the tail of the log has gone past the QUOTAOFF record, but
	 * before the last dquot modification, those dquots __will__
	 * recover, and that's not good.
	 *
	 * So, we have QUOTAOFF start and end logitems; the start
	 * logitem won't get overwritten until the end logitem appears...
	 */
	error = xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
	if (error) {
		
		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
		goto out_unlock;
	}

	if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
	    ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
		mutex_unlock(&q->qi_quotaofflock);
		xfs_qm_destroy_quotainfo(mp);
		return (0);
	}

	if ((dqtype & XFS_QMOPT_UQUOTA) && q->qi_uquotaip) {
		IRELE(q->qi_uquotaip);
		q->qi_uquotaip = NULL;
	}
	if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && q->qi_gquotaip) {
		IRELE(q->qi_gquotaip);
		q->qi_gquotaip = NULL;
	}

out_unlock:
	mutex_unlock(&q->qi_quotaofflock);
	return error;
}
int
xfs_qm_scall_quotaon(
	xfs_mount_t	*mp,
	uint		flags)
{
	int		error;
	uint		qf;
	__int64_t	sbflags;

	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
	flags &= ~(XFS_ALL_QUOTA_ACCT);

	sbflags = 0;

	if (flags == 0) {
		xfs_debug(mp, "%s: zero flags, m_qflags=%x\n",
			__func__, mp->m_qflags);
		return XFS_ERROR(EINVAL);
	}

	
	ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);

	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
	    (flags & XFS_UQUOTA_ENFD))
	    ||
	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
	    (flags & XFS_GQUOTA_ACCT) == 0 &&
	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
	    (flags & XFS_OQUOTA_ENFD))) {
		xfs_debug(mp,
			"%s: Can't enforce without acct, flags=%x sbflags=%x\n",
			__func__, flags, mp->m_sb.sb_qflags);
		return XFS_ERROR(EINVAL);
	}
	if ((mp->m_qflags & flags) == flags)
		return XFS_ERROR(EEXIST);

	spin_lock(&mp->m_sb_lock);
	qf = mp->m_sb.sb_qflags;
	mp->m_sb.sb_qflags = qf | flags;
	spin_unlock(&mp->m_sb_lock);

	if ((qf & flags) == flags && sbflags == 0)
		return XFS_ERROR(EEXIST);
	sbflags |= XFS_SB_QFLAGS;

	if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
		return (error);
	if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
	     (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
	     ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
	     (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
	     ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
	     (mp->m_qflags & XFS_GQUOTA_ACCT)) ||
	    (flags & XFS_ALL_QUOTA_ENFD) == 0)
		return (0);

	if (! XFS_IS_QUOTA_RUNNING(mp))
		return XFS_ERROR(ESRCH);

	mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
	mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
	mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);

	return (0);
}