diff options
author | Christoph Hellwig <hch@lst.de> | 2010-09-05 21:44:22 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-10-18 16:07:36 -0400 |
commit | 52fda114249578311776b25da9f73a9c34f4fd8c (patch) | |
tree | 976f100c5b68d799bb552280dad2f3bf9b078c90 /fs/xfs/quota/xfs_qm.c | |
parent | 447223520520b17d3b6d0631aa4838fbaf8eddb4 (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/xfs/quota/xfs_qm.c')
-rw-r--r-- | fs/xfs/quota/xfs_qm.c | 203 |
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 | */ | ||
1208 | STATIC int | ||
1209 | xfs_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 | */ |
1554 | STATIC void | 1474 | STATIC int |
1555 | xfs_qm_quotacheck_dqadjust( | 1475 | xfs_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 | ||
1592 | STATIC int | 1529 | STATIC 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 | |||
1646 | error0: | ||
1647 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1648 | IRELE(ip); | ||
1649 | *res = BULKSTAT_RV_GIVEUP; | ||
1650 | return error; | ||
1732 | } | 1651 | } |
1733 | 1652 | ||
1734 | /* | 1653 | /* |