aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2010-09-05 21:44:22 -0400
committerAlex Elder <aelder@sgi.com>2010-10-18 16:07:36 -0400
commit52fda114249578311776b25da9f73a9c34f4fd8c (patch)
tree976f100c5b68d799bb552280dad2f3bf9b078c90 /fs
parent447223520520b17d3b6d0631aa4838fbaf8eddb4 (diff)
xfs: simplify xfs_qm_dqusage_adjust
There is no need to have the users and group/project quota locked at the same time. Get rid of xfs_qm_dqget_noattach and just do a xfs_qm_dqget inside xfs_qm_quotacheck_dqadjust for the quota we are operating on right now. The new version of xfs_qm_quotacheck_dqadjust holds the inode lock over it's operations, which is not a problem as it simply increments counters and there is no concern about log contention during mount time. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/quota/xfs_qm.c203
1 files changed, 61 insertions, 142 deletions
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 9a92407109a1..121f632213a7 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -1199,87 +1199,6 @@ xfs_qm_list_destroy(
1199 mutex_destroy(&(list->qh_lock)); 1199 mutex_destroy(&(list->qh_lock));
1200} 1200}
1201 1201
1202
1203/*
1204 * Stripped down version of dqattach. This doesn't attach, or even look at the
1205 * dquots attached to the inode. The rationale is that there won't be any
1206 * attached at the time this is called from quotacheck.
1207 */
1208STATIC int
1209xfs_qm_dqget_noattach(
1210 xfs_inode_t *ip,
1211 xfs_dquot_t **O_udqpp,
1212 xfs_dquot_t **O_gdqpp)
1213{
1214 int error;
1215 xfs_mount_t *mp;
1216 xfs_dquot_t *udqp, *gdqp;
1217
1218 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1219 mp = ip->i_mount;
1220 udqp = NULL;
1221 gdqp = NULL;
1222
1223 if (XFS_IS_UQUOTA_ON(mp)) {
1224 ASSERT(ip->i_udquot == NULL);
1225 /*
1226 * We want the dquot allocated if it doesn't exist.
1227 */
1228 if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
1229 XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
1230 &udqp))) {
1231 /*
1232 * Shouldn't be able to turn off quotas here.
1233 */
1234 ASSERT(error != ESRCH);
1235 ASSERT(error != ENOENT);
1236 return error;
1237 }
1238 ASSERT(udqp);
1239 }
1240
1241 if (XFS_IS_OQUOTA_ON(mp)) {
1242 ASSERT(ip->i_gdquot == NULL);
1243 if (udqp)
1244 xfs_dqunlock(udqp);
1245 error = XFS_IS_GQUOTA_ON(mp) ?
1246 xfs_qm_dqget(mp, ip,
1247 ip->i_d.di_gid, XFS_DQ_GROUP,
1248 XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
1249 &gdqp) :
1250 xfs_qm_dqget(mp, ip,
1251 ip->i_d.di_projid, XFS_DQ_PROJ,
1252 XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
1253 &gdqp);
1254 if (error) {
1255 if (udqp)
1256 xfs_qm_dqrele(udqp);
1257 ASSERT(error != ESRCH);
1258 ASSERT(error != ENOENT);
1259 return error;
1260 }
1261 ASSERT(gdqp);
1262
1263 /* Reacquire the locks in the right order */
1264 if (udqp) {
1265 if (! xfs_qm_dqlock_nowait(udqp)) {
1266 xfs_dqunlock(gdqp);
1267 xfs_dqlock(udqp);
1268 xfs_dqlock(gdqp);
1269 }
1270 }
1271 }
1272
1273 *O_udqpp = udqp;
1274 *O_gdqpp = gdqp;
1275
1276#ifdef QUOTADEBUG
1277 if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
1278 if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
1279#endif
1280 return 0;
1281}
1282
1283/* 1202/*
1284 * Create an inode and return with a reference already taken, but unlocked 1203 * Create an inode and return with a reference already taken, but unlocked
1285 * This is how we create quota inodes 1204 * This is how we create quota inodes
@@ -1546,18 +1465,34 @@ xfs_qm_dqiterate(
1546 1465
1547/* 1466/*
1548 * Called by dqusage_adjust in doing a quotacheck. 1467 * Called by dqusage_adjust in doing a quotacheck.
1549 * Given the inode, and a dquot (either USR or GRP, doesn't matter), 1468 *
1550 * this updates its incore copy as well as the buffer copy. This is 1469 * Given the inode, and a dquot id this updates both the incore dqout as well
1551 * so that once the quotacheck is done, we can just log all the buffers, 1470 * as the buffer copy. This is so that once the quotacheck is done, we can
1552 * as opposed to logging numerous updates to individual dquots. 1471 * just log all the buffers, as opposed to logging numerous updates to
1472 * individual dquots.
1553 */ 1473 */
1554STATIC void 1474STATIC int
1555xfs_qm_quotacheck_dqadjust( 1475xfs_qm_quotacheck_dqadjust(
1556 xfs_dquot_t *dqp, 1476 struct xfs_inode *ip,
1477 xfs_dqid_t id,
1478 uint type,
1557 xfs_qcnt_t nblks, 1479 xfs_qcnt_t nblks,
1558 xfs_qcnt_t rtblks) 1480 xfs_qcnt_t rtblks)
1559{ 1481{
1560 ASSERT(XFS_DQ_IS_LOCKED(dqp)); 1482 struct xfs_mount *mp = ip->i_mount;
1483 struct xfs_dquot *dqp;
1484 int error;
1485
1486 error = xfs_qm_dqget(mp, ip, id, type,
1487 XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp);
1488 if (error) {
1489 /*
1490 * Shouldn't be able to turn off quotas here.
1491 */
1492 ASSERT(error != ESRCH);
1493 ASSERT(error != ENOENT);
1494 return error;
1495 }
1561 1496
1562 trace_xfs_dqadjust(dqp); 1497 trace_xfs_dqadjust(dqp);
1563 1498
@@ -1582,11 +1517,13 @@ xfs_qm_quotacheck_dqadjust(
1582 * There are no timers for the default values set in the root dquot. 1517 * There are no timers for the default values set in the root dquot.
1583 */ 1518 */
1584 if (dqp->q_core.d_id) { 1519 if (dqp->q_core.d_id) {
1585 xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core); 1520 xfs_qm_adjust_dqlimits(mp, &dqp->q_core);
1586 xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); 1521 xfs_qm_adjust_dqtimers(mp, &dqp->q_core);
1587 } 1522 }
1588 1523
1589 dqp->dq_flags |= XFS_DQ_DIRTY; 1524 dqp->dq_flags |= XFS_DQ_DIRTY;
1525 xfs_qm_dqput(dqp);
1526 return 0;
1590} 1527}
1591 1528
1592STATIC int 1529STATIC int
@@ -1629,8 +1566,7 @@ xfs_qm_dqusage_adjust(
1629 int *res) /* result code value */ 1566 int *res) /* result code value */
1630{ 1567{
1631 xfs_inode_t *ip; 1568 xfs_inode_t *ip;
1632 xfs_dquot_t *udqp, *gdqp; 1569 xfs_qcnt_t nblks, rtblks = 0;
1633 xfs_qcnt_t nblks, rtblks;
1634 int error; 1570 int error;
1635 1571
1636 ASSERT(XFS_IS_QUOTA_RUNNING(mp)); 1572 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -1650,51 +1586,24 @@ xfs_qm_dqusage_adjust(
1650 * the case in all other instances. It's OK that we do this because 1586 * the case in all other instances. It's OK that we do this because
1651 * quotacheck is done only at mount time. 1587 * quotacheck is done only at mount time.
1652 */ 1588 */
1653 if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) { 1589 error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip);
1590 if (error) {
1654 *res = BULKSTAT_RV_NOTHING; 1591 *res = BULKSTAT_RV_NOTHING;
1655 return error; 1592 return error;
1656 } 1593 }
1657 1594
1658 /* 1595 ASSERT(ip->i_delayed_blks == 0);
1659 * Obtain the locked dquots. In case of an error (eg. allocation
1660 * fails for ENOSPC), we return the negative of the error number
1661 * to bulkstat, so that it can get propagated to quotacheck() and
1662 * making us disable quotas for the file system.
1663 */
1664 if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
1665 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1666 IRELE(ip);
1667 *res = BULKSTAT_RV_GIVEUP;
1668 return error;
1669 }
1670 1596
1671 rtblks = 0; 1597 if (XFS_IS_REALTIME_INODE(ip)) {
1672 if (! XFS_IS_REALTIME_INODE(ip)) {
1673 nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
1674 } else {
1675 /* 1598 /*
1676 * Walk thru the extent list and count the realtime blocks. 1599 * Walk thru the extent list and count the realtime blocks.
1677 */ 1600 */
1678 if ((error = xfs_qm_get_rtblks(ip, &rtblks))) { 1601 error = xfs_qm_get_rtblks(ip, &rtblks);
1679 xfs_iunlock(ip, XFS_ILOCK_EXCL); 1602 if (error)
1680 IRELE(ip); 1603 goto error0;
1681 if (udqp)
1682 xfs_qm_dqput(udqp);
1683 if (gdqp)
1684 xfs_qm_dqput(gdqp);
1685 *res = BULKSTAT_RV_GIVEUP;
1686 return error;
1687 }
1688 nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
1689 } 1604 }
1690 ASSERT(ip->i_delayed_blks == 0);
1691 1605
1692 /* 1606 nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
1693 * We can't release the inode while holding its dquot locks.
1694 * The inode can go into inactive and might try to acquire the dquotlocks.
1695 * So, just unlock here and do a vn_rele at the end.
1696 */
1697 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1698 1607
1699 /* 1608 /*
1700 * Add the (disk blocks and inode) resources occupied by this 1609 * Add the (disk blocks and inode) resources occupied by this
@@ -1709,26 +1618,36 @@ xfs_qm_dqusage_adjust(
1709 * and quotaoffs don't race. (Quotachecks happen at mount time only). 1618 * and quotaoffs don't race. (Quotachecks happen at mount time only).
1710 */ 1619 */
1711 if (XFS_IS_UQUOTA_ON(mp)) { 1620 if (XFS_IS_UQUOTA_ON(mp)) {
1712 ASSERT(udqp); 1621 error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_uid,
1713 xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); 1622 XFS_DQ_USER, nblks, rtblks);
1714 xfs_qm_dqput(udqp); 1623 if (error)
1624 goto error0;
1715 } 1625 }
1716 if (XFS_IS_OQUOTA_ON(mp)) { 1626
1717 ASSERT(gdqp); 1627 if (XFS_IS_GQUOTA_ON(mp)) {
1718 xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); 1628 error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_gid,
1719 xfs_qm_dqput(gdqp); 1629 XFS_DQ_GROUP, nblks, rtblks);
1630 if (error)
1631 goto error0;
1720 } 1632 }
1721 /*
1722 * Now release the inode. This will send it to 'inactive', and
1723 * possibly even free blocks.
1724 */
1725 IRELE(ip);
1726 1633
1727 /* 1634 if (XFS_IS_PQUOTA_ON(mp)) {
1728 * Goto next inode. 1635 error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_projid,
1729 */ 1636 XFS_DQ_PROJ, nblks, rtblks);
1637 if (error)
1638 goto error0;
1639 }
1640
1641 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1642 IRELE(ip);
1730 *res = BULKSTAT_RV_DIDONE; 1643 *res = BULKSTAT_RV_DIDONE;
1731 return 0; 1644 return 0;
1645
1646error0:
1647 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1648 IRELE(ip);
1649 *res = BULKSTAT_RV_GIVEUP;
1650 return error;
1732} 1651}
1733 1652
1734/* 1653/*