diff options
Diffstat (limited to 'fs/xfs/quota/xfs_qm.c')
-rw-r--r-- | fs/xfs/quota/xfs_qm.c | 221 |
1 files changed, 69 insertions, 152 deletions
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 9a92407109a1..f8e854b4fde8 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
@@ -55,8 +55,6 @@ uint ndquot; | |||
55 | kmem_zone_t *qm_dqzone; | 55 | kmem_zone_t *qm_dqzone; |
56 | kmem_zone_t *qm_dqtrxzone; | 56 | kmem_zone_t *qm_dqtrxzone; |
57 | 57 | ||
58 | static cred_t xfs_zerocr; | ||
59 | |||
60 | STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); | 58 | STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); |
61 | STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); | 59 | STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); |
62 | 60 | ||
@@ -837,7 +835,7 @@ xfs_qm_dqattach_locked( | |||
837 | xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, | 835 | xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, |
838 | flags & XFS_QMOPT_DQALLOC, | 836 | flags & XFS_QMOPT_DQALLOC, |
839 | ip->i_udquot, &ip->i_gdquot) : | 837 | ip->i_udquot, &ip->i_gdquot) : |
840 | xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ, | 838 | xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ, |
841 | flags & XFS_QMOPT_DQALLOC, | 839 | flags & XFS_QMOPT_DQALLOC, |
842 | ip->i_udquot, &ip->i_gdquot); | 840 | ip->i_udquot, &ip->i_gdquot); |
843 | /* | 841 | /* |
@@ -1199,87 +1197,6 @@ xfs_qm_list_destroy( | |||
1199 | mutex_destroy(&(list->qh_lock)); | 1197 | mutex_destroy(&(list->qh_lock)); |
1200 | } | 1198 | } |
1201 | 1199 | ||
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 | /* | 1200 | /* |
1284 | * Create an inode and return with a reference already taken, but unlocked | 1201 | * Create an inode and return with a reference already taken, but unlocked |
1285 | * This is how we create quota inodes | 1202 | * This is how we create quota inodes |
@@ -1305,8 +1222,8 @@ xfs_qm_qino_alloc( | |||
1305 | return error; | 1222 | return error; |
1306 | } | 1223 | } |
1307 | 1224 | ||
1308 | if ((error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, | 1225 | error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, &committed); |
1309 | &xfs_zerocr, 0, 1, ip, &committed))) { | 1226 | if (error) { |
1310 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | | 1227 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | |
1311 | XFS_TRANS_ABORT); | 1228 | XFS_TRANS_ABORT); |
1312 | return error; | 1229 | return error; |
@@ -1516,7 +1433,7 @@ xfs_qm_dqiterate( | |||
1516 | rablkcnt = map[i+1].br_blockcount; | 1433 | rablkcnt = map[i+1].br_blockcount; |
1517 | rablkno = map[i+1].br_startblock; | 1434 | rablkno = map[i+1].br_startblock; |
1518 | while (rablkcnt--) { | 1435 | while (rablkcnt--) { |
1519 | xfs_baread(mp->m_ddev_targp, | 1436 | xfs_buf_readahead(mp->m_ddev_targp, |
1520 | XFS_FSB_TO_DADDR(mp, rablkno), | 1437 | XFS_FSB_TO_DADDR(mp, rablkno), |
1521 | mp->m_quotainfo->qi_dqchunklen); | 1438 | mp->m_quotainfo->qi_dqchunklen); |
1522 | rablkno++; | 1439 | rablkno++; |
@@ -1546,18 +1463,34 @@ xfs_qm_dqiterate( | |||
1546 | 1463 | ||
1547 | /* | 1464 | /* |
1548 | * Called by dqusage_adjust in doing a quotacheck. | 1465 | * Called by dqusage_adjust in doing a quotacheck. |
1549 | * Given the inode, and a dquot (either USR or GRP, doesn't matter), | 1466 | * |
1550 | * this updates its incore copy as well as the buffer copy. This is | 1467 | * 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, | 1468 | * 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. | 1469 | * just log all the buffers, as opposed to logging numerous updates to |
1470 | * individual dquots. | ||
1553 | */ | 1471 | */ |
1554 | STATIC void | 1472 | STATIC int |
1555 | xfs_qm_quotacheck_dqadjust( | 1473 | xfs_qm_quotacheck_dqadjust( |
1556 | xfs_dquot_t *dqp, | 1474 | struct xfs_inode *ip, |
1475 | xfs_dqid_t id, | ||
1476 | uint type, | ||
1557 | xfs_qcnt_t nblks, | 1477 | xfs_qcnt_t nblks, |
1558 | xfs_qcnt_t rtblks) | 1478 | xfs_qcnt_t rtblks) |
1559 | { | 1479 | { |
1560 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | 1480 | struct xfs_mount *mp = ip->i_mount; |
1481 | struct xfs_dquot *dqp; | ||
1482 | int error; | ||
1483 | |||
1484 | error = xfs_qm_dqget(mp, ip, id, type, | ||
1485 | XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp); | ||
1486 | if (error) { | ||
1487 | /* | ||
1488 | * Shouldn't be able to turn off quotas here. | ||
1489 | */ | ||
1490 | ASSERT(error != ESRCH); | ||
1491 | ASSERT(error != ENOENT); | ||
1492 | return error; | ||
1493 | } | ||
1561 | 1494 | ||
1562 | trace_xfs_dqadjust(dqp); | 1495 | trace_xfs_dqadjust(dqp); |
1563 | 1496 | ||
@@ -1582,11 +1515,13 @@ xfs_qm_quotacheck_dqadjust( | |||
1582 | * There are no timers for the default values set in the root dquot. | 1515 | * There are no timers for the default values set in the root dquot. |
1583 | */ | 1516 | */ |
1584 | if (dqp->q_core.d_id) { | 1517 | if (dqp->q_core.d_id) { |
1585 | xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core); | 1518 | xfs_qm_adjust_dqlimits(mp, &dqp->q_core); |
1586 | xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); | 1519 | xfs_qm_adjust_dqtimers(mp, &dqp->q_core); |
1587 | } | 1520 | } |
1588 | 1521 | ||
1589 | dqp->dq_flags |= XFS_DQ_DIRTY; | 1522 | dqp->dq_flags |= XFS_DQ_DIRTY; |
1523 | xfs_qm_dqput(dqp); | ||
1524 | return 0; | ||
1590 | } | 1525 | } |
1591 | 1526 | ||
1592 | STATIC int | 1527 | STATIC int |
@@ -1629,8 +1564,7 @@ xfs_qm_dqusage_adjust( | |||
1629 | int *res) /* result code value */ | 1564 | int *res) /* result code value */ |
1630 | { | 1565 | { |
1631 | xfs_inode_t *ip; | 1566 | xfs_inode_t *ip; |
1632 | xfs_dquot_t *udqp, *gdqp; | 1567 | xfs_qcnt_t nblks, rtblks = 0; |
1633 | xfs_qcnt_t nblks, rtblks; | ||
1634 | int error; | 1568 | int error; |
1635 | 1569 | ||
1636 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); | 1570 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); |
@@ -1650,51 +1584,24 @@ xfs_qm_dqusage_adjust( | |||
1650 | * the case in all other instances. It's OK that we do this because | 1584 | * the case in all other instances. It's OK that we do this because |
1651 | * quotacheck is done only at mount time. | 1585 | * quotacheck is done only at mount time. |
1652 | */ | 1586 | */ |
1653 | if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) { | 1587 | error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip); |
1588 | if (error) { | ||
1654 | *res = BULKSTAT_RV_NOTHING; | 1589 | *res = BULKSTAT_RV_NOTHING; |
1655 | return error; | 1590 | return error; |
1656 | } | 1591 | } |
1657 | 1592 | ||
1658 | /* | 1593 | 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 | 1594 | ||
1671 | rtblks = 0; | 1595 | 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 | /* | 1596 | /* |
1676 | * Walk thru the extent list and count the realtime blocks. | 1597 | * Walk thru the extent list and count the realtime blocks. |
1677 | */ | 1598 | */ |
1678 | if ((error = xfs_qm_get_rtblks(ip, &rtblks))) { | 1599 | error = xfs_qm_get_rtblks(ip, &rtblks); |
1679 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1600 | if (error) |
1680 | IRELE(ip); | 1601 | 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 | } | 1602 | } |
1690 | ASSERT(ip->i_delayed_blks == 0); | ||
1691 | 1603 | ||
1692 | /* | 1604 | 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 | 1605 | ||
1699 | /* | 1606 | /* |
1700 | * Add the (disk blocks and inode) resources occupied by this | 1607 | * Add the (disk blocks and inode) resources occupied by this |
@@ -1709,26 +1616,36 @@ xfs_qm_dqusage_adjust( | |||
1709 | * and quotaoffs don't race. (Quotachecks happen at mount time only). | 1616 | * and quotaoffs don't race. (Quotachecks happen at mount time only). |
1710 | */ | 1617 | */ |
1711 | if (XFS_IS_UQUOTA_ON(mp)) { | 1618 | if (XFS_IS_UQUOTA_ON(mp)) { |
1712 | ASSERT(udqp); | 1619 | error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_uid, |
1713 | xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); | 1620 | XFS_DQ_USER, nblks, rtblks); |
1714 | xfs_qm_dqput(udqp); | 1621 | if (error) |
1622 | goto error0; | ||
1715 | } | 1623 | } |
1716 | if (XFS_IS_OQUOTA_ON(mp)) { | 1624 | |
1717 | ASSERT(gdqp); | 1625 | if (XFS_IS_GQUOTA_ON(mp)) { |
1718 | xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); | 1626 | error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_gid, |
1719 | xfs_qm_dqput(gdqp); | 1627 | XFS_DQ_GROUP, nblks, rtblks); |
1628 | if (error) | ||
1629 | goto error0; | ||
1720 | } | 1630 | } |
1721 | /* | ||
1722 | * Now release the inode. This will send it to 'inactive', and | ||
1723 | * possibly even free blocks. | ||
1724 | */ | ||
1725 | IRELE(ip); | ||
1726 | 1631 | ||
1727 | /* | 1632 | if (XFS_IS_PQUOTA_ON(mp)) { |
1728 | * Goto next inode. | 1633 | error = xfs_qm_quotacheck_dqadjust(ip, xfs_get_projid(ip), |
1729 | */ | 1634 | XFS_DQ_PROJ, nblks, rtblks); |
1635 | if (error) | ||
1636 | goto error0; | ||
1637 | } | ||
1638 | |||
1639 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1640 | IRELE(ip); | ||
1730 | *res = BULKSTAT_RV_DIDONE; | 1641 | *res = BULKSTAT_RV_DIDONE; |
1731 | return 0; | 1642 | return 0; |
1643 | |||
1644 | error0: | ||
1645 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1646 | IRELE(ip); | ||
1647 | *res = BULKSTAT_RV_GIVEUP; | ||
1648 | return error; | ||
1732 | } | 1649 | } |
1733 | 1650 | ||
1734 | /* | 1651 | /* |
@@ -2224,7 +2141,7 @@ xfs_qm_write_sb_changes( | |||
2224 | 2141 | ||
2225 | 2142 | ||
2226 | /* | 2143 | /* |
2227 | * Given an inode, a uid and gid (from cred_t) make sure that we have | 2144 | * Given an inode, a uid, gid and prid make sure that we have |
2228 | * allocated relevant dquot(s) on disk, and that we won't exceed inode | 2145 | * allocated relevant dquot(s) on disk, and that we won't exceed inode |
2229 | * quotas by creating this file. | 2146 | * quotas by creating this file. |
2230 | * This also attaches dquot(s) to the given inode after locking it, | 2147 | * This also attaches dquot(s) to the given inode after locking it, |
@@ -2332,7 +2249,7 @@ xfs_qm_vop_dqalloc( | |||
2332 | xfs_dqunlock(gq); | 2249 | xfs_dqunlock(gq); |
2333 | } | 2250 | } |
2334 | } else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) { | 2251 | } else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) { |
2335 | if (ip->i_d.di_projid != prid) { | 2252 | if (xfs_get_projid(ip) != prid) { |
2336 | xfs_iunlock(ip, lockflags); | 2253 | xfs_iunlock(ip, lockflags); |
2337 | if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid, | 2254 | if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid, |
2338 | XFS_DQ_PROJ, | 2255 | XFS_DQ_PROJ, |
@@ -2454,7 +2371,7 @@ xfs_qm_vop_chown_reserve( | |||
2454 | } | 2371 | } |
2455 | if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) { | 2372 | if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) { |
2456 | if (XFS_IS_PQUOTA_ON(ip->i_mount) && | 2373 | if (XFS_IS_PQUOTA_ON(ip->i_mount) && |
2457 | ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id)) | 2374 | xfs_get_projid(ip) != be32_to_cpu(gdqp->q_core.d_id)) |
2458 | prjflags = XFS_QMOPT_ENOSPC; | 2375 | prjflags = XFS_QMOPT_ENOSPC; |
2459 | 2376 | ||
2460 | if (prjflags || | 2377 | if (prjflags || |
@@ -2558,7 +2475,7 @@ xfs_qm_vop_create_dqattach( | |||
2558 | ip->i_gdquot = gdqp; | 2475 | ip->i_gdquot = gdqp; |
2559 | ASSERT(XFS_IS_OQUOTA_ON(mp)); | 2476 | ASSERT(XFS_IS_OQUOTA_ON(mp)); |
2560 | ASSERT((XFS_IS_GQUOTA_ON(mp) ? | 2477 | ASSERT((XFS_IS_GQUOTA_ON(mp) ? |
2561 | ip->i_d.di_gid : ip->i_d.di_projid) == | 2478 | ip->i_d.di_gid : xfs_get_projid(ip)) == |
2562 | be32_to_cpu(gdqp->q_core.d_id)); | 2479 | be32_to_cpu(gdqp->q_core.d_id)); |
2563 | xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1); | 2480 | xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1); |
2564 | } | 2481 | } |