aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2015-02-23 05:19:53 -0500
committerDave Chinner <david@fromorbit.com>2015-02-23 05:19:53 -0500
commite88b64ea1f3da64dbb52636377be295c90367377 (patch)
tree0031d3ed6f296981fdcd2b9f4cf3cebc8b557ab8 /fs/xfs
parent501ab32387533924b211cacff36d19296414ec0b (diff)
xfs: use generic percpu counters for free inode counter
XFS has hand-rolled per-cpu counters for the superblock since before there was any generic implementation. The free inode counter is not used for any limit enforcement - the per-AG free inode counters are used during allocation to determine if there are inode available for allocation. Hence we don't need any of the complexity of the hand-rolled counters and we can simply replace them with generic per-cpu counters similar to the inode counter. This version introduces a xfs_mod_ifree() helper function from Christoph Hellwig. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/libxfs/xfs_sb.c1
-rw-r--r--fs/xfs/xfs_fsops.c2
-rw-r--r--fs/xfs/xfs_mount.c76
-rw-r--r--fs/xfs/xfs_mount.h2
-rw-r--r--fs/xfs/xfs_super.c4
-rw-r--r--fs/xfs/xfs_trans.c5
6 files changed, 42 insertions, 48 deletions
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 017cb2fc53eb..b66aeab99cfb 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -772,6 +772,7 @@ xfs_log_sb(
772 struct xfs_buf *bp = xfs_trans_getsb(tp, mp, 0); 772 struct xfs_buf *bp = xfs_trans_getsb(tp, mp, 0);
773 773
774 mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); 774 mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount);
775 mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree);
775 776
776 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); 777 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb);
777 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); 778 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF);
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index b87a6f92263b..a1ca9c2b8c00 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -639,11 +639,11 @@ xfs_fs_counts(
639{ 639{
640 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); 640 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
641 cnt->allocino = percpu_counter_read_positive(&mp->m_icount); 641 cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
642 cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
642 643
643 spin_lock(&mp->m_sb_lock); 644 spin_lock(&mp->m_sb_lock);
644 cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); 645 cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
645 cnt->freertx = mp->m_sb.sb_frextents; 646 cnt->freertx = mp->m_sb.sb_frextents;
646 cnt->freeino = mp->m_sb.sb_ifree;
647 spin_unlock(&mp->m_sb_lock); 647 spin_unlock(&mp->m_sb_lock);
648 return 0; 648 return 0;
649} 649}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 702ea6a7e648..650e8f18cd2a 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1114,6 +1114,20 @@ xfs_mod_icount(
1114 return 0; 1114 return 0;
1115} 1115}
1116 1116
1117
1118int
1119xfs_mod_ifree(
1120 struct xfs_mount *mp,
1121 int64_t delta)
1122{
1123 percpu_counter_add(&mp->m_ifree, delta);
1124 if (percpu_counter_compare(&mp->m_ifree, 0) < 0) {
1125 ASSERT(0);
1126 percpu_counter_add(&mp->m_ifree, -delta);
1127 return -EINVAL;
1128 }
1129 return 0;
1130}
1117/* 1131/*
1118 * xfs_mod_incore_sb_unlocked() is a utility routine commonly used to apply 1132 * xfs_mod_incore_sb_unlocked() is a utility routine commonly used to apply
1119 * a delta to a specified field in the in-core superblock. Simply 1133 * a delta to a specified field in the in-core superblock. Simply
@@ -1142,17 +1156,9 @@ xfs_mod_incore_sb_unlocked(
1142 */ 1156 */
1143 switch (field) { 1157 switch (field) {
1144 case XFS_SBS_ICOUNT: 1158 case XFS_SBS_ICOUNT:
1145 ASSERT(0);
1146 return -ENOSPC;
1147 case XFS_SBS_IFREE: 1159 case XFS_SBS_IFREE:
1148 lcounter = (long long)mp->m_sb.sb_ifree; 1160 ASSERT(0);
1149 lcounter += delta; 1161 return -EINVAL;
1150 if (lcounter < 0) {
1151 ASSERT(0);
1152 return -EINVAL;
1153 }
1154 mp->m_sb.sb_ifree = lcounter;
1155 return 0;
1156 case XFS_SBS_FDBLOCKS: 1162 case XFS_SBS_FDBLOCKS:
1157 lcounter = (long long) 1163 lcounter = (long long)
1158 mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); 1164 mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
@@ -1502,7 +1508,6 @@ xfs_icsb_cpu_notify(
1502 case CPU_ONLINE: 1508 case CPU_ONLINE:
1503 case CPU_ONLINE_FROZEN: 1509 case CPU_ONLINE_FROZEN:
1504 xfs_icsb_lock(mp); 1510 xfs_icsb_lock(mp);
1505 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
1506 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); 1511 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
1507 xfs_icsb_unlock(mp); 1512 xfs_icsb_unlock(mp);
1508 break; 1513 break;
@@ -1513,15 +1518,12 @@ xfs_icsb_cpu_notify(
1513 * re-enable the counters. */ 1518 * re-enable the counters. */
1514 xfs_icsb_lock(mp); 1519 xfs_icsb_lock(mp);
1515 spin_lock(&mp->m_sb_lock); 1520 spin_lock(&mp->m_sb_lock);
1516 xfs_icsb_disable_counter(mp, XFS_SBS_IFREE);
1517 xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS); 1521 xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS);
1518 1522
1519 mp->m_sb.sb_ifree += cntp->icsb_ifree;
1520 mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks; 1523 mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks;
1521 1524
1522 memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); 1525 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
1523 1526
1524 xfs_icsb_balance_counter_locked(mp, XFS_SBS_IFREE, 0);
1525 xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0); 1527 xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0);
1526 spin_unlock(&mp->m_sb_lock); 1528 spin_unlock(&mp->m_sb_lock);
1527 xfs_icsb_unlock(mp); 1529 xfs_icsb_unlock(mp);
@@ -1544,10 +1546,14 @@ xfs_icsb_init_counters(
1544 if (error) 1546 if (error)
1545 return error; 1547 return error;
1546 1548
1549 error = percpu_counter_init(&mp->m_ifree, 0, GFP_KERNEL);
1550 if (error)
1551 goto free_icount;
1552
1547 mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t); 1553 mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t);
1548 if (!mp->m_sb_cnts) { 1554 if (!mp->m_sb_cnts) {
1549 percpu_counter_destroy(&mp->m_icount); 1555 error = -ENOMEM;
1550 return -ENOMEM; 1556 goto free_ifree;
1551 } 1557 }
1552 1558
1553 for_each_online_cpu(i) { 1559 for_each_online_cpu(i) {
@@ -1570,6 +1576,12 @@ xfs_icsb_init_counters(
1570#endif /* CONFIG_HOTPLUG_CPU */ 1576#endif /* CONFIG_HOTPLUG_CPU */
1571 1577
1572 return 0; 1578 return 0;
1579
1580free_ifree:
1581 percpu_counter_destroy(&mp->m_ifree);
1582free_icount:
1583 percpu_counter_destroy(&mp->m_icount);
1584 return error;
1573} 1585}
1574 1586
1575void 1587void
@@ -1577,6 +1589,7 @@ xfs_icsb_reinit_counters(
1577 xfs_mount_t *mp) 1589 xfs_mount_t *mp)
1578{ 1590{
1579 percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount); 1591 percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount);
1592 percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree);
1580 1593
1581 xfs_icsb_lock(mp); 1594 xfs_icsb_lock(mp);
1582 /* 1595 /*
@@ -1584,7 +1597,6 @@ xfs_icsb_reinit_counters(
1584 * initial balance kicks us off correctly 1597 * initial balance kicks us off correctly
1585 */ 1598 */
1586 mp->m_icsb_counters = -1; 1599 mp->m_icsb_counters = -1;
1587 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
1588 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); 1600 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
1589 xfs_icsb_unlock(mp); 1601 xfs_icsb_unlock(mp);
1590} 1602}
@@ -1599,6 +1611,7 @@ xfs_icsb_destroy_counters(
1599 } 1611 }
1600 1612
1601 percpu_counter_destroy(&mp->m_icount); 1613 percpu_counter_destroy(&mp->m_icount);
1614 percpu_counter_destroy(&mp->m_ifree);
1602 1615
1603 mutex_destroy(&mp->m_icsb_mutex); 1616 mutex_destroy(&mp->m_icsb_mutex);
1604} 1617}
@@ -1662,7 +1675,6 @@ xfs_icsb_count(
1662 1675
1663 for_each_online_cpu(i) { 1676 for_each_online_cpu(i) {
1664 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); 1677 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
1665 cnt->icsb_ifree += cntp->icsb_ifree;
1666 cnt->icsb_fdblocks += cntp->icsb_fdblocks; 1678 cnt->icsb_fdblocks += cntp->icsb_fdblocks;
1667 } 1679 }
1668 1680
@@ -1675,7 +1687,7 @@ xfs_icsb_counter_disabled(
1675 xfs_mount_t *mp, 1687 xfs_mount_t *mp,
1676 xfs_sb_field_t field) 1688 xfs_sb_field_t field)
1677{ 1689{
1678 ASSERT((field >= XFS_SBS_IFREE) && (field <= XFS_SBS_FDBLOCKS)); 1690 ASSERT(field == XFS_SBS_FDBLOCKS);
1679 return test_bit(field, &mp->m_icsb_counters); 1691 return test_bit(field, &mp->m_icsb_counters);
1680} 1692}
1681 1693
@@ -1686,7 +1698,7 @@ xfs_icsb_disable_counter(
1686{ 1698{
1687 xfs_icsb_cnts_t cnt; 1699 xfs_icsb_cnts_t cnt;
1688 1700
1689 ASSERT((field >= XFS_SBS_IFREE) && (field <= XFS_SBS_FDBLOCKS)); 1701 ASSERT(field == XFS_SBS_FDBLOCKS);
1690 1702
1691 /* 1703 /*
1692 * If we are already disabled, then there is nothing to do 1704 * If we are already disabled, then there is nothing to do
@@ -1705,9 +1717,6 @@ xfs_icsb_disable_counter(
1705 1717
1706 xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT); 1718 xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT);
1707 switch(field) { 1719 switch(field) {
1708 case XFS_SBS_IFREE:
1709 mp->m_sb.sb_ifree = cnt.icsb_ifree;
1710 break;
1711 case XFS_SBS_FDBLOCKS: 1720 case XFS_SBS_FDBLOCKS:
1712 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; 1721 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
1713 break; 1722 break;
@@ -1729,15 +1738,12 @@ xfs_icsb_enable_counter(
1729 xfs_icsb_cnts_t *cntp; 1738 xfs_icsb_cnts_t *cntp;
1730 int i; 1739 int i;
1731 1740
1732 ASSERT((field >= XFS_SBS_IFREE) && (field <= XFS_SBS_FDBLOCKS)); 1741 ASSERT(field == XFS_SBS_FDBLOCKS);
1733 1742
1734 xfs_icsb_lock_all_counters(mp); 1743 xfs_icsb_lock_all_counters(mp);
1735 for_each_online_cpu(i) { 1744 for_each_online_cpu(i) {
1736 cntp = per_cpu_ptr(mp->m_sb_cnts, i); 1745 cntp = per_cpu_ptr(mp->m_sb_cnts, i);
1737 switch (field) { 1746 switch (field) {
1738 case XFS_SBS_IFREE:
1739 cntp->icsb_ifree = count + resid;
1740 break;
1741 case XFS_SBS_FDBLOCKS: 1747 case XFS_SBS_FDBLOCKS:
1742 cntp->icsb_fdblocks = count + resid; 1748 cntp->icsb_fdblocks = count + resid;
1743 break; 1749 break;
@@ -1760,8 +1766,6 @@ xfs_icsb_sync_counters_locked(
1760 1766
1761 xfs_icsb_count(mp, &cnt, flags); 1767 xfs_icsb_count(mp, &cnt, flags);
1762 1768
1763 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE))
1764 mp->m_sb.sb_ifree = cnt.icsb_ifree;
1765 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS)) 1769 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
1766 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; 1770 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
1767} 1771}
@@ -1813,12 +1817,6 @@ xfs_icsb_balance_counter_locked(
1813 1817
1814 /* update counters - first CPU gets residual*/ 1818 /* update counters - first CPU gets residual*/
1815 switch (field) { 1819 switch (field) {
1816 case XFS_SBS_IFREE:
1817 count = mp->m_sb.sb_ifree;
1818 resid = do_div(count, weight);
1819 if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
1820 return;
1821 break;
1822 case XFS_SBS_FDBLOCKS: 1820 case XFS_SBS_FDBLOCKS:
1823 count = mp->m_sb.sb_fdblocks; 1821 count = mp->m_sb.sb_fdblocks;
1824 resid = do_div(count, weight); 1822 resid = do_div(count, weight);
@@ -1873,14 +1871,6 @@ again:
1873 } 1871 }
1874 1872
1875 switch (field) { 1873 switch (field) {
1876 case XFS_SBS_IFREE:
1877 lcounter = icsbp->icsb_ifree;
1878 lcounter += delta;
1879 if (unlikely(lcounter < 0))
1880 goto balance_counter;
1881 icsbp->icsb_ifree = lcounter;
1882 break;
1883
1884 case XFS_SBS_FDBLOCKS: 1874 case XFS_SBS_FDBLOCKS:
1885 BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0); 1875 BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0);
1886 1876
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 76b18c8c58c5..7ce997d43d81 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -84,6 +84,7 @@ typedef struct xfs_mount {
84 struct xfs_sb m_sb; /* copy of fs superblock */ 84 struct xfs_sb m_sb; /* copy of fs superblock */
85 spinlock_t m_sb_lock; /* sb counter lock */ 85 spinlock_t m_sb_lock; /* sb counter lock */
86 struct percpu_counter m_icount; /* allocated inodes counter */ 86 struct percpu_counter m_icount; /* allocated inodes counter */
87 struct percpu_counter m_ifree; /* free inodes counter */
87 88
88 struct xfs_buf *m_sb_bp; /* buffer for superblock */ 89 struct xfs_buf *m_sb_bp; /* buffer for superblock */
89 char *m_fsname; /* filesystem name */ 90 char *m_fsname; /* filesystem name */
@@ -391,6 +392,7 @@ extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
391extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, 392extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
392 uint, int); 393 uint, int);
393extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta); 394extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta);
395extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta);
394extern int xfs_mount_log_sb(xfs_mount_t *); 396extern int xfs_mount_log_sb(xfs_mount_t *);
395extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); 397extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
396extern int xfs_readsb(xfs_mount_t *, int); 398extern int xfs_readsb(xfs_mount_t *, int);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 0aa4428bfa31..049147776ee1 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1086,6 +1086,7 @@ xfs_fs_statfs(
1086 struct xfs_inode *ip = XFS_I(dentry->d_inode); 1086 struct xfs_inode *ip = XFS_I(dentry->d_inode);
1087 __uint64_t fakeinos, id; 1087 __uint64_t fakeinos, id;
1088 __uint64_t icount; 1088 __uint64_t icount;
1089 __uint64_t ifree;
1089 xfs_extlen_t lsize; 1090 xfs_extlen_t lsize;
1090 __int64_t ffree; 1091 __int64_t ffree;
1091 1092
@@ -1098,6 +1099,7 @@ xfs_fs_statfs(
1098 1099
1099 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); 1100 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
1100 icount = percpu_counter_sum(&mp->m_icount); 1101 icount = percpu_counter_sum(&mp->m_icount);
1102 ifree = percpu_counter_sum(&mp->m_ifree);
1101 1103
1102 spin_lock(&mp->m_sb_lock); 1104 spin_lock(&mp->m_sb_lock);
1103 statp->f_bsize = sbp->sb_blocksize; 1105 statp->f_bsize = sbp->sb_blocksize;
@@ -1118,7 +1120,7 @@ xfs_fs_statfs(
1118 sbp->sb_icount); 1120 sbp->sb_icount);
1119 1121
1120 /* make sure statp->f_ffree does not underflow */ 1122 /* make sure statp->f_ffree does not underflow */
1121 ffree = statp->f_files - (icount - sbp->sb_ifree); 1123 ffree = statp->f_files - (icount - ifree);
1122 statp->f_ffree = max_t(__int64_t, ffree, 0); 1124 statp->f_ffree = max_t(__int64_t, ffree, 0);
1123 1125
1124 spin_unlock(&mp->m_sb_lock); 1126 spin_unlock(&mp->m_sb_lock);
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 9bc742b65f24..68680ce67547 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -560,8 +560,7 @@ xfs_trans_unreserve_and_mod_sb(
560 } 560 }
561 561
562 if (ifreedelta) { 562 if (ifreedelta) {
563 error = xfs_icsb_modify_counters(mp, XFS_SBS_IFREE, 563 error = xfs_mod_ifree(mp, ifreedelta);
564 ifreedelta, rsvd);
565 if (error) 564 if (error)
566 goto out_undo_icount; 565 goto out_undo_icount;
567 } 566 }
@@ -630,7 +629,7 @@ xfs_trans_unreserve_and_mod_sb(
630 629
631out_undo_ifreecount: 630out_undo_ifreecount:
632 if (ifreedelta) 631 if (ifreedelta)
633 xfs_icsb_modify_counters(mp, XFS_SBS_IFREE, -ifreedelta, rsvd); 632 xfs_mod_ifree(mp, -ifreedelta);
634out_undo_icount: 633out_undo_icount:
635 if (idelta) 634 if (idelta)
636 xfs_mod_icount(mp, -idelta); 635 xfs_mod_icount(mp, -idelta);