|
@@ -1199,87 +1199,6 @@ xfs_qm_list_destroy(
|
|
|
mutex_destroy(&(list->qh_lock));
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-/*
|
|
|
- * Stripped down version of dqattach. This doesn't attach, or even look at the
|
|
|
- * dquots attached to the inode. The rationale is that there won't be any
|
|
|
- * attached at the time this is called from quotacheck.
|
|
|
- */
|
|
|
-STATIC int
|
|
|
-xfs_qm_dqget_noattach(
|
|
|
- xfs_inode_t *ip,
|
|
|
- xfs_dquot_t **O_udqpp,
|
|
|
- xfs_dquot_t **O_gdqpp)
|
|
|
-{
|
|
|
- int error;
|
|
|
- xfs_mount_t *mp;
|
|
|
- xfs_dquot_t *udqp, *gdqp;
|
|
|
-
|
|
|
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
|
|
|
- mp = ip->i_mount;
|
|
|
- udqp = NULL;
|
|
|
- gdqp = NULL;
|
|
|
-
|
|
|
- if (XFS_IS_UQUOTA_ON(mp)) {
|
|
|
- ASSERT(ip->i_udquot == NULL);
|
|
|
- /*
|
|
|
- * We want the dquot allocated if it doesn't exist.
|
|
|
- */
|
|
|
- if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
|
|
|
- XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
|
|
|
- &udqp))) {
|
|
|
- /*
|
|
|
- * Shouldn't be able to turn off quotas here.
|
|
|
- */
|
|
|
- ASSERT(error != ESRCH);
|
|
|
- ASSERT(error != ENOENT);
|
|
|
- return error;
|
|
|
- }
|
|
|
- ASSERT(udqp);
|
|
|
- }
|
|
|
-
|
|
|
- if (XFS_IS_OQUOTA_ON(mp)) {
|
|
|
- ASSERT(ip->i_gdquot == NULL);
|
|
|
- if (udqp)
|
|
|
- xfs_dqunlock(udqp);
|
|
|
- error = XFS_IS_GQUOTA_ON(mp) ?
|
|
|
- xfs_qm_dqget(mp, ip,
|
|
|
- ip->i_d.di_gid, XFS_DQ_GROUP,
|
|
|
- XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
|
|
|
- &gdqp) :
|
|
|
- xfs_qm_dqget(mp, ip,
|
|
|
- ip->i_d.di_projid, XFS_DQ_PROJ,
|
|
|
- XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
|
|
|
- &gdqp);
|
|
|
- if (error) {
|
|
|
- if (udqp)
|
|
|
- xfs_qm_dqrele(udqp);
|
|
|
- ASSERT(error != ESRCH);
|
|
|
- ASSERT(error != ENOENT);
|
|
|
- return error;
|
|
|
- }
|
|
|
- ASSERT(gdqp);
|
|
|
-
|
|
|
- /* Reacquire the locks in the right order */
|
|
|
- if (udqp) {
|
|
|
- if (! xfs_qm_dqlock_nowait(udqp)) {
|
|
|
- xfs_dqunlock(gdqp);
|
|
|
- xfs_dqlock(udqp);
|
|
|
- xfs_dqlock(gdqp);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- *O_udqpp = udqp;
|
|
|
- *O_gdqpp = gdqp;
|
|
|
-
|
|
|
-#ifdef QUOTADEBUG
|
|
|
- if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
|
|
|
- if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
|
|
|
-#endif
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Create an inode and return with a reference already taken, but unlocked
|
|
|
* This is how we create quota inodes
|
|
@@ -1546,18 +1465,34 @@ xfs_qm_dqiterate(
|
|
|
|
|
|
/*
|
|
|
* Called by dqusage_adjust in doing a quotacheck.
|
|
|
- * Given the inode, and a dquot (either USR or GRP, doesn't matter),
|
|
|
- * this updates its incore copy as well as the buffer copy. This is
|
|
|
- * so that once the quotacheck is done, we can just log all the buffers,
|
|
|
- * as opposed to logging numerous updates to individual dquots.
|
|
|
+ *
|
|
|
+ * Given the inode, and a dquot id this updates both the incore dqout as well
|
|
|
+ * as the buffer copy. This is so that once the quotacheck is done, we can
|
|
|
+ * just log all the buffers, as opposed to logging numerous updates to
|
|
|
+ * individual dquots.
|
|
|
*/
|
|
|
-STATIC void
|
|
|
+STATIC int
|
|
|
xfs_qm_quotacheck_dqadjust(
|
|
|
- xfs_dquot_t *dqp,
|
|
|
+ struct xfs_inode *ip,
|
|
|
+ xfs_dqid_t id,
|
|
|
+ uint type,
|
|
|
xfs_qcnt_t nblks,
|
|
|
xfs_qcnt_t rtblks)
|
|
|
{
|
|
|
- ASSERT(XFS_DQ_IS_LOCKED(dqp));
|
|
|
+ struct xfs_mount *mp = ip->i_mount;
|
|
|
+ struct xfs_dquot *dqp;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ error = xfs_qm_dqget(mp, ip, id, type,
|
|
|
+ XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp);
|
|
|
+ if (error) {
|
|
|
+ /*
|
|
|
+ * Shouldn't be able to turn off quotas here.
|
|
|
+ */
|
|
|
+ ASSERT(error != ESRCH);
|
|
|
+ ASSERT(error != ENOENT);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
|
|
|
trace_xfs_dqadjust(dqp);
|
|
|
|
|
@@ -1582,11 +1517,13 @@ xfs_qm_quotacheck_dqadjust(
|
|
|
* There are no timers for the default values set in the root dquot.
|
|
|
*/
|
|
|
if (dqp->q_core.d_id) {
|
|
|
- xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core);
|
|
|
- xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
|
|
|
+ xfs_qm_adjust_dqlimits(mp, &dqp->q_core);
|
|
|
+ xfs_qm_adjust_dqtimers(mp, &dqp->q_core);
|
|
|
}
|
|
|
|
|
|
dqp->dq_flags |= XFS_DQ_DIRTY;
|
|
|
+ xfs_qm_dqput(dqp);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
STATIC int
|
|
@@ -1629,8 +1566,7 @@ xfs_qm_dqusage_adjust(
|
|
|
int *res) /* result code value */
|
|
|
{
|
|
|
xfs_inode_t *ip;
|
|
|
- xfs_dquot_t *udqp, *gdqp;
|
|
|
- xfs_qcnt_t nblks, rtblks;
|
|
|
+ xfs_qcnt_t nblks, rtblks = 0;
|
|
|
int error;
|
|
|
|
|
|
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
|
|
@@ -1650,51 +1586,24 @@ xfs_qm_dqusage_adjust(
|
|
|
* the case in all other instances. It's OK that we do this because
|
|
|
* quotacheck is done only at mount time.
|
|
|
*/
|
|
|
- if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) {
|
|
|
+ error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip);
|
|
|
+ if (error) {
|
|
|
*res = BULKSTAT_RV_NOTHING;
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Obtain the locked dquots. In case of an error (eg. allocation
|
|
|
- * fails for ENOSPC), we return the negative of the error number
|
|
|
- * to bulkstat, so that it can get propagated to quotacheck() and
|
|
|
- * making us disable quotas for the file system.
|
|
|
- */
|
|
|
- if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
|
|
|
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
- IRELE(ip);
|
|
|
- *res = BULKSTAT_RV_GIVEUP;
|
|
|
- return error;
|
|
|
- }
|
|
|
+ ASSERT(ip->i_delayed_blks == 0);
|
|
|
|
|
|
- rtblks = 0;
|
|
|
- if (! XFS_IS_REALTIME_INODE(ip)) {
|
|
|
- nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
|
|
|
- } else {
|
|
|
+ if (XFS_IS_REALTIME_INODE(ip)) {
|
|
|
/*
|
|
|
* Walk thru the extent list and count the realtime blocks.
|
|
|
*/
|
|
|
- if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
|
|
|
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
- IRELE(ip);
|
|
|
- if (udqp)
|
|
|
- xfs_qm_dqput(udqp);
|
|
|
- if (gdqp)
|
|
|
- xfs_qm_dqput(gdqp);
|
|
|
- *res = BULKSTAT_RV_GIVEUP;
|
|
|
- return error;
|
|
|
- }
|
|
|
- nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
|
|
|
+ error = xfs_qm_get_rtblks(ip, &rtblks);
|
|
|
+ if (error)
|
|
|
+ goto error0;
|
|
|
}
|
|
|
- ASSERT(ip->i_delayed_blks == 0);
|
|
|
|
|
|
- /*
|
|
|
- * We can't release the inode while holding its dquot locks.
|
|
|
- * The inode can go into inactive and might try to acquire the dquotlocks.
|
|
|
- * So, just unlock here and do a vn_rele at the end.
|
|
|
- */
|
|
|
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
+ nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
|
|
|
|
|
|
/*
|
|
|
* Add the (disk blocks and inode) resources occupied by this
|
|
@@ -1709,26 +1618,36 @@ xfs_qm_dqusage_adjust(
|
|
|
* and quotaoffs don't race. (Quotachecks happen at mount time only).
|
|
|
*/
|
|
|
if (XFS_IS_UQUOTA_ON(mp)) {
|
|
|
- ASSERT(udqp);
|
|
|
- xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
|
|
|
- xfs_qm_dqput(udqp);
|
|
|
+ error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_uid,
|
|
|
+ XFS_DQ_USER, nblks, rtblks);
|
|
|
+ if (error)
|
|
|
+ goto error0;
|
|
|
}
|
|
|
- if (XFS_IS_OQUOTA_ON(mp)) {
|
|
|
- ASSERT(gdqp);
|
|
|
- xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
|
|
|
- xfs_qm_dqput(gdqp);
|
|
|
+
|
|
|
+ if (XFS_IS_GQUOTA_ON(mp)) {
|
|
|
+ error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_gid,
|
|
|
+ XFS_DQ_GROUP, nblks, rtblks);
|
|
|
+ if (error)
|
|
|
+ goto error0;
|
|
|
}
|
|
|
- /*
|
|
|
- * Now release the inode. This will send it to 'inactive', and
|
|
|
- * possibly even free blocks.
|
|
|
- */
|
|
|
- IRELE(ip);
|
|
|
|
|
|
- /*
|
|
|
- * Goto next inode.
|
|
|
- */
|
|
|
+ if (XFS_IS_PQUOTA_ON(mp)) {
|
|
|
+ error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_projid,
|
|
|
+ XFS_DQ_PROJ, nblks, rtblks);
|
|
|
+ if (error)
|
|
|
+ goto error0;
|
|
|
+ }
|
|
|
+
|
|
|
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
+ IRELE(ip);
|
|
|
*res = BULKSTAT_RV_DIDONE;
|
|
|
return 0;
|
|
|
+
|
|
|
+error0:
|
|
|
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
+ IRELE(ip);
|
|
|
+ *res = BULKSTAT_RV_GIVEUP;
|
|
|
+ return error;
|
|
|
}
|
|
|
|
|
|
/*
|