aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_mount.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
commit1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch)
treef5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /fs/xfs/xfs_mount.c
parentac58c9059da8886b5e8cde012a80266b18ca146e (diff)
parent674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff)
Merge branch 'linus'
Diffstat (limited to 'fs/xfs/xfs_mount.c')
-rw-r--r--fs/xfs/xfs_mount.c646
1 files changed, 629 insertions, 17 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 62188ea392c7..20e8abc16d18 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -51,11 +51,32 @@ STATIC int xfs_uuid_mount(xfs_mount_t *);
51STATIC void xfs_uuid_unmount(xfs_mount_t *mp); 51STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
52STATIC void xfs_unmountfs_wait(xfs_mount_t *); 52STATIC void xfs_unmountfs_wait(xfs_mount_t *);
53 53
54
55#ifdef HAVE_PERCPU_SB
56STATIC void xfs_icsb_destroy_counters(xfs_mount_t *);
57STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int);
58STATIC void xfs_icsb_sync_counters(xfs_mount_t *);
59STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
60 int, int);
61STATIC int xfs_icsb_modify_counters_locked(xfs_mount_t *, xfs_sb_field_t,
62 int, int);
63STATIC int xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
64
65#else
66
67#define xfs_icsb_destroy_counters(mp) do { } while (0)
68#define xfs_icsb_balance_counter(mp, a, b) do { } while (0)
69#define xfs_icsb_sync_counters(mp) do { } while (0)
70#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)
71#define xfs_icsb_modify_counters_locked(mp, a, b, c) do { } while (0)
72
73#endif
74
54static const struct { 75static const struct {
55 short offset; 76 short offset;
56 short type; /* 0 = integer 77 short type; /* 0 = integer
57 * 1 = binary / string (no translation) 78 * 1 = binary / string (no translation)
58 */ 79 */
59} xfs_sb_info[] = { 80} xfs_sb_info[] = {
60 { offsetof(xfs_sb_t, sb_magicnum), 0 }, 81 { offsetof(xfs_sb_t, sb_magicnum), 0 },
61 { offsetof(xfs_sb_t, sb_blocksize), 0 }, 82 { offsetof(xfs_sb_t, sb_blocksize), 0 },
@@ -113,7 +134,11 @@ xfs_mount_init(void)
113{ 134{
114 xfs_mount_t *mp; 135 xfs_mount_t *mp;
115 136
116 mp = kmem_zalloc(sizeof(*mp), KM_SLEEP); 137 mp = kmem_zalloc(sizeof(xfs_mount_t), KM_SLEEP);
138
139 if (xfs_icsb_init_counters(mp)) {
140 mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
141 }
117 142
118 AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); 143 AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail");
119 spinlock_init(&mp->m_sb_lock, "xfs_sb"); 144 spinlock_init(&mp->m_sb_lock, "xfs_sb");
@@ -136,8 +161,8 @@ xfs_mount_init(void)
136 */ 161 */
137void 162void
138xfs_mount_free( 163xfs_mount_free(
139 xfs_mount_t *mp, 164 xfs_mount_t *mp,
140 int remove_bhv) 165 int remove_bhv)
141{ 166{
142 if (mp->m_ihash) 167 if (mp->m_ihash)
143 xfs_ihash_free(mp); 168 xfs_ihash_free(mp);
@@ -177,6 +202,7 @@ xfs_mount_free(
177 VFS_REMOVEBHV(vfsp, &mp->m_bhv); 202 VFS_REMOVEBHV(vfsp, &mp->m_bhv);
178 } 203 }
179 204
205 xfs_icsb_destroy_counters(mp);
180 kmem_free(mp, sizeof(xfs_mount_t)); 206 kmem_free(mp, sizeof(xfs_mount_t));
181} 207}
182 208
@@ -242,9 +268,12 @@ xfs_mount_validate_sb(
242 sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || 268 sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG ||
243 sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || 269 sbp->sb_inodesize < XFS_DINODE_MIN_SIZE ||
244 sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || 270 sbp->sb_inodesize > XFS_DINODE_MAX_SIZE ||
271 sbp->sb_inodelog < XFS_DINODE_MIN_LOG ||
272 sbp->sb_inodelog > XFS_DINODE_MAX_LOG ||
273 (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) ||
245 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || 274 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||
246 (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || 275 (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) ||
247 sbp->sb_imax_pct > 100)) { 276 (sbp->sb_imax_pct > 100 || sbp->sb_imax_pct < 1))) {
248 cmn_err(CE_WARN, "XFS: SB sanity check 1 failed"); 277 cmn_err(CE_WARN, "XFS: SB sanity check 1 failed");
249 XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(3)", 278 XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(3)",
250 XFS_ERRLEVEL_LOW, mp, sbp); 279 XFS_ERRLEVEL_LOW, mp, sbp);
@@ -527,6 +556,10 @@ xfs_readsb(xfs_mount_t *mp)
527 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); 556 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
528 } 557 }
529 558
559 xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
560 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
561 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
562
530 mp->m_sb_bp = bp; 563 mp->m_sb_bp = bp;
531 xfs_buf_relse(bp); 564 xfs_buf_relse(bp);
532 ASSERT(XFS_BUF_VALUSEMA(bp) > 0); 565 ASSERT(XFS_BUF_VALUSEMA(bp) > 0);
@@ -1154,6 +1187,9 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
1154 sbp = xfs_getsb(mp, 0); 1187 sbp = xfs_getsb(mp, 0);
1155 if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY || 1188 if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY ||
1156 XFS_FORCED_SHUTDOWN(mp))) { 1189 XFS_FORCED_SHUTDOWN(mp))) {
1190
1191 xfs_icsb_sync_counters(mp);
1192
1157 /* 1193 /*
1158 * mark shared-readonly if desired 1194 * mark shared-readonly if desired
1159 */ 1195 */
@@ -1227,7 +1263,6 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
1227 1263
1228 xfs_trans_log_buf(tp, bp, first, last); 1264 xfs_trans_log_buf(tp, bp, first, last);
1229} 1265}
1230
1231/* 1266/*
1232 * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply 1267 * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply
1233 * a delta to a specified field in the in-core superblock. Simply 1268 * a delta to a specified field in the in-core superblock. Simply
@@ -1237,7 +1272,7 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
1237 * 1272 *
1238 * The SB_LOCK must be held when this routine is called. 1273 * The SB_LOCK must be held when this routine is called.
1239 */ 1274 */
1240STATIC int 1275int
1241xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, 1276xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field,
1242 int delta, int rsvd) 1277 int delta, int rsvd)
1243{ 1278{
@@ -1406,9 +1441,26 @@ xfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd)
1406 unsigned long s; 1441 unsigned long s;
1407 int status; 1442 int status;
1408 1443
1409 s = XFS_SB_LOCK(mp); 1444 /* check for per-cpu counters */
1410 status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); 1445 switch (field) {
1411 XFS_SB_UNLOCK(mp, s); 1446#ifdef HAVE_PERCPU_SB
1447 case XFS_SBS_ICOUNT:
1448 case XFS_SBS_IFREE:
1449 case XFS_SBS_FDBLOCKS:
1450 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
1451 status = xfs_icsb_modify_counters(mp, field,
1452 delta, rsvd);
1453 break;
1454 }
1455 /* FALLTHROUGH */
1456#endif
1457 default:
1458 s = XFS_SB_LOCK(mp);
1459 status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
1460 XFS_SB_UNLOCK(mp, s);
1461 break;
1462 }
1463
1412 return status; 1464 return status;
1413} 1465}
1414 1466
@@ -1445,8 +1497,26 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd)
1445 * from the loop so we'll fall into the undo loop 1497 * from the loop so we'll fall into the undo loop
1446 * below. 1498 * below.
1447 */ 1499 */
1448 status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, 1500 switch (msbp->msb_field) {
1449 msbp->msb_delta, rsvd); 1501#ifdef HAVE_PERCPU_SB
1502 case XFS_SBS_ICOUNT:
1503 case XFS_SBS_IFREE:
1504 case XFS_SBS_FDBLOCKS:
1505 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
1506 status = xfs_icsb_modify_counters_locked(mp,
1507 msbp->msb_field,
1508 msbp->msb_delta, rsvd);
1509 break;
1510 }
1511 /* FALLTHROUGH */
1512#endif
1513 default:
1514 status = xfs_mod_incore_sb_unlocked(mp,
1515 msbp->msb_field,
1516 msbp->msb_delta, rsvd);
1517 break;
1518 }
1519
1450 if (status != 0) { 1520 if (status != 0) {
1451 break; 1521 break;
1452 } 1522 }
@@ -1463,8 +1533,28 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd)
1463 if (status != 0) { 1533 if (status != 0) {
1464 msbp--; 1534 msbp--;
1465 while (msbp >= msb) { 1535 while (msbp >= msb) {
1466 status = xfs_mod_incore_sb_unlocked(mp, 1536 switch (msbp->msb_field) {
1467 msbp->msb_field, -(msbp->msb_delta), rsvd); 1537#ifdef HAVE_PERCPU_SB
1538 case XFS_SBS_ICOUNT:
1539 case XFS_SBS_IFREE:
1540 case XFS_SBS_FDBLOCKS:
1541 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
1542 status =
1543 xfs_icsb_modify_counters_locked(mp,
1544 msbp->msb_field,
1545 -(msbp->msb_delta),
1546 rsvd);
1547 break;
1548 }
1549 /* FALLTHROUGH */
1550#endif
1551 default:
1552 status = xfs_mod_incore_sb_unlocked(mp,
1553 msbp->msb_field,
1554 -(msbp->msb_delta),
1555 rsvd);
1556 break;
1557 }
1468 ASSERT(status == 0); 1558 ASSERT(status == 0);
1469 msbp--; 1559 msbp--;
1470 } 1560 }
@@ -1577,3 +1667,525 @@ xfs_mount_log_sbunit(
1577 xfs_mod_sb(tp, fields); 1667 xfs_mod_sb(tp, fields);
1578 xfs_trans_commit(tp, 0, NULL); 1668 xfs_trans_commit(tp, 0, NULL);
1579} 1669}
1670
1671
1672#ifdef HAVE_PERCPU_SB
1673/*
1674 * Per-cpu incore superblock counters
1675 *
1676 * Simple concept, difficult implementation
1677 *
1678 * Basically, replace the incore superblock counters with a distributed per cpu
1679 * counter for contended fields (e.g. free block count).
1680 *
1681 * Difficulties arise in that the incore sb is used for ENOSPC checking, and
1682 * hence needs to be accurately read when we are running low on space. Hence
1683 * there is a method to enable and disable the per-cpu counters based on how
1684 * much "stuff" is available in them.
1685 *
1686 * Basically, a counter is enabled if there is enough free resource to justify
1687 * running a per-cpu fast-path. If the per-cpu counter runs out (i.e. a local
1688 * ENOSPC), then we disable the counters to synchronise all callers and
1689 * re-distribute the available resources.
1690 *
1691 * If, once we redistributed the available resources, we still get a failure,
1692 * we disable the per-cpu counter and go through the slow path.
1693 *
1694 * The slow path is the current xfs_mod_incore_sb() function. This means that
1695 * when we disable a per-cpu counter, we need to drain it's resources back to
1696 * the global superblock. We do this after disabling the counter to prevent
1697 * more threads from queueing up on the counter.
1698 *
1699 * Essentially, this means that we still need a lock in the fast path to enable
1700 * synchronisation between the global counters and the per-cpu counters. This
1701 * is not a problem because the lock will be local to a CPU almost all the time
1702 * and have little contention except when we get to ENOSPC conditions.
1703 *
1704 * Basically, this lock becomes a barrier that enables us to lock out the fast
1705 * path while we do things like enabling and disabling counters and
1706 * synchronising the counters.
1707 *
1708 * Locking rules:
1709 *
1710 * 1. XFS_SB_LOCK() before picking up per-cpu locks
1711 * 2. per-cpu locks always picked up via for_each_online_cpu() order
1712 * 3. accurate counter sync requires XFS_SB_LOCK + per cpu locks
1713 * 4. modifying per-cpu counters requires holding per-cpu lock
1714 * 5. modifying global counters requires holding XFS_SB_LOCK
1715 * 6. enabling or disabling a counter requires holding the XFS_SB_LOCK
1716 * and _none_ of the per-cpu locks.
1717 *
1718 * Disabled counters are only ever re-enabled by a balance operation
1719 * that results in more free resources per CPU than a given threshold.
1720 * To ensure counters don't remain disabled, they are rebalanced when
1721 * the global resource goes above a higher threshold (i.e. some hysteresis
1722 * is present to prevent thrashing).
1723 */
1724
1725/*
1726 * hot-plug CPU notifier support.
1727 *
1728 * We cannot use the hotcpu_register() function because it does
1729 * not allow notifier instances. We need a notifier per filesystem
1730 * as we need to be able to identify the filesystem to balance
1731 * the counters out. This is acheived by having a notifier block
1732 * embedded in the xfs_mount_t and doing pointer magic to get the
1733 * mount pointer from the notifier block address.
1734 */
1735STATIC int
1736xfs_icsb_cpu_notify(
1737 struct notifier_block *nfb,
1738 unsigned long action,
1739 void *hcpu)
1740{
1741 xfs_icsb_cnts_t *cntp;
1742 xfs_mount_t *mp;
1743 int s;
1744
1745 mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier);
1746 cntp = (xfs_icsb_cnts_t *)
1747 per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
1748 switch (action) {
1749 case CPU_UP_PREPARE:
1750 /* Easy Case - initialize the area and locks, and
1751 * then rebalance when online does everything else for us. */
1752 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
1753 break;
1754 case CPU_ONLINE:
1755 xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
1756 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
1757 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
1758 break;
1759 case CPU_DEAD:
1760 /* Disable all the counters, then fold the dead cpu's
1761 * count into the total on the global superblock and
1762 * re-enable the counters. */
1763 s = XFS_SB_LOCK(mp);
1764 xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT);
1765 xfs_icsb_disable_counter(mp, XFS_SBS_IFREE);
1766 xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS);
1767
1768 mp->m_sb.sb_icount += cntp->icsb_icount;
1769 mp->m_sb.sb_ifree += cntp->icsb_ifree;
1770 mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks;
1771
1772 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
1773
1774 xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, XFS_ICSB_SB_LOCKED);
1775 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, XFS_ICSB_SB_LOCKED);
1776 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, XFS_ICSB_SB_LOCKED);
1777 XFS_SB_UNLOCK(mp, s);
1778 break;
1779 }
1780
1781 return NOTIFY_OK;
1782}
1783
1784int
1785xfs_icsb_init_counters(
1786 xfs_mount_t *mp)
1787{
1788 xfs_icsb_cnts_t *cntp;
1789 int i;
1790
1791 mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t);
1792 if (mp->m_sb_cnts == NULL)
1793 return -ENOMEM;
1794
1795 mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
1796 mp->m_icsb_notifier.priority = 0;
1797 register_cpu_notifier(&mp->m_icsb_notifier);
1798
1799 for_each_online_cpu(i) {
1800 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
1801 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
1802 }
1803 /*
1804 * start with all counters disabled so that the
1805 * initial balance kicks us off correctly
1806 */
1807 mp->m_icsb_counters = -1;
1808 return 0;
1809}
1810
1811STATIC void
1812xfs_icsb_destroy_counters(
1813 xfs_mount_t *mp)
1814{
1815 if (mp->m_sb_cnts) {
1816 unregister_cpu_notifier(&mp->m_icsb_notifier);
1817 free_percpu(mp->m_sb_cnts);
1818 }
1819}
1820
1821STATIC inline void
1822xfs_icsb_lock_cntr(
1823 xfs_icsb_cnts_t *icsbp)
1824{
1825 while (test_and_set_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags)) {
1826 ndelay(1000);
1827 }
1828}
1829
1830STATIC inline void
1831xfs_icsb_unlock_cntr(
1832 xfs_icsb_cnts_t *icsbp)
1833{
1834 clear_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags);
1835}
1836
1837
1838STATIC inline void
1839xfs_icsb_lock_all_counters(
1840 xfs_mount_t *mp)
1841{
1842 xfs_icsb_cnts_t *cntp;
1843 int i;
1844
1845 for_each_online_cpu(i) {
1846 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
1847 xfs_icsb_lock_cntr(cntp);
1848 }
1849}
1850
1851STATIC inline void
1852xfs_icsb_unlock_all_counters(
1853 xfs_mount_t *mp)
1854{
1855 xfs_icsb_cnts_t *cntp;
1856 int i;
1857
1858 for_each_online_cpu(i) {
1859 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
1860 xfs_icsb_unlock_cntr(cntp);
1861 }
1862}
1863
1864STATIC void
1865xfs_icsb_count(
1866 xfs_mount_t *mp,
1867 xfs_icsb_cnts_t *cnt,
1868 int flags)
1869{
1870 xfs_icsb_cnts_t *cntp;
1871 int i;
1872
1873 memset(cnt, 0, sizeof(xfs_icsb_cnts_t));
1874
1875 if (!(flags & XFS_ICSB_LAZY_COUNT))
1876 xfs_icsb_lock_all_counters(mp);
1877
1878 for_each_online_cpu(i) {
1879 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
1880 cnt->icsb_icount += cntp->icsb_icount;
1881 cnt->icsb_ifree += cntp->icsb_ifree;
1882 cnt->icsb_fdblocks += cntp->icsb_fdblocks;
1883 }
1884
1885 if (!(flags & XFS_ICSB_LAZY_COUNT))
1886 xfs_icsb_unlock_all_counters(mp);
1887}
1888
1889STATIC int
1890xfs_icsb_counter_disabled(
1891 xfs_mount_t *mp,
1892 xfs_sb_field_t field)
1893{
1894 ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
1895 return test_bit(field, &mp->m_icsb_counters);
1896}
1897
1898STATIC int
1899xfs_icsb_disable_counter(
1900 xfs_mount_t *mp,
1901 xfs_sb_field_t field)
1902{
1903 xfs_icsb_cnts_t cnt;
1904
1905 ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
1906
1907 xfs_icsb_lock_all_counters(mp);
1908 if (!test_and_set_bit(field, &mp->m_icsb_counters)) {
1909 /* drain back to superblock */
1910
1911 xfs_icsb_count(mp, &cnt, XFS_ICSB_SB_LOCKED|XFS_ICSB_LAZY_COUNT);
1912 switch(field) {
1913 case XFS_SBS_ICOUNT:
1914 mp->m_sb.sb_icount = cnt.icsb_icount;
1915 break;
1916 case XFS_SBS_IFREE:
1917 mp->m_sb.sb_ifree = cnt.icsb_ifree;
1918 break;
1919 case XFS_SBS_FDBLOCKS:
1920 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
1921 break;
1922 default:
1923 BUG();
1924 }
1925 }
1926
1927 xfs_icsb_unlock_all_counters(mp);
1928
1929 return 0;
1930}
1931
1932STATIC void
1933xfs_icsb_enable_counter(
1934 xfs_mount_t *mp,
1935 xfs_sb_field_t field,
1936 uint64_t count,
1937 uint64_t resid)
1938{
1939 xfs_icsb_cnts_t *cntp;
1940 int i;
1941
1942 ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
1943
1944 xfs_icsb_lock_all_counters(mp);
1945 for_each_online_cpu(i) {
1946 cntp = per_cpu_ptr(mp->m_sb_cnts, i);
1947 switch (field) {
1948 case XFS_SBS_ICOUNT:
1949 cntp->icsb_icount = count + resid;
1950 break;
1951 case XFS_SBS_IFREE:
1952 cntp->icsb_ifree = count + resid;
1953 break;
1954 case XFS_SBS_FDBLOCKS:
1955 cntp->icsb_fdblocks = count + resid;
1956 break;
1957 default:
1958 BUG();
1959 break;
1960 }
1961 resid = 0;
1962 }
1963 clear_bit(field, &mp->m_icsb_counters);
1964 xfs_icsb_unlock_all_counters(mp);
1965}
1966
1967STATIC void
1968xfs_icsb_sync_counters_int(
1969 xfs_mount_t *mp,
1970 int flags)
1971{
1972 xfs_icsb_cnts_t cnt;
1973 int s;
1974
1975 /* Pass 1: lock all counters */
1976 if ((flags & XFS_ICSB_SB_LOCKED) == 0)
1977 s = XFS_SB_LOCK(mp);
1978
1979 xfs_icsb_count(mp, &cnt, flags);
1980
1981 /* Step 3: update mp->m_sb fields */
1982 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT))
1983 mp->m_sb.sb_icount = cnt.icsb_icount;
1984 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE))
1985 mp->m_sb.sb_ifree = cnt.icsb_ifree;
1986 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
1987 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
1988
1989 if ((flags & XFS_ICSB_SB_LOCKED) == 0)
1990 XFS_SB_UNLOCK(mp, s);
1991}
1992
1993/*
1994 * Accurate update of per-cpu counters to incore superblock
1995 */
1996STATIC void
1997xfs_icsb_sync_counters(
1998 xfs_mount_t *mp)
1999{
2000 xfs_icsb_sync_counters_int(mp, 0);
2001}
2002
2003/*
2004 * lazy addition used for things like df, background sb syncs, etc
2005 */
2006void
2007xfs_icsb_sync_counters_lazy(
2008 xfs_mount_t *mp)
2009{
2010 xfs_icsb_sync_counters_int(mp, XFS_ICSB_LAZY_COUNT);
2011}
2012
2013/*
2014 * Balance and enable/disable counters as necessary.
2015 *
2016 * Thresholds for re-enabling counters are somewhat magic.
2017 * inode counts are chosen to be the same number as single
2018 * on disk allocation chunk per CPU, and free blocks is
2019 * something far enough zero that we aren't going thrash
2020 * when we get near ENOSPC.
2021 */
2022#define XFS_ICSB_INO_CNTR_REENABLE 64
2023#define XFS_ICSB_FDBLK_CNTR_REENABLE 512
2024STATIC void
2025xfs_icsb_balance_counter(
2026 xfs_mount_t *mp,
2027 xfs_sb_field_t field,
2028 int flags)
2029{
2030 uint64_t count, resid = 0;
2031 int weight = num_online_cpus();
2032 int s;
2033
2034 if (!(flags & XFS_ICSB_SB_LOCKED))
2035 s = XFS_SB_LOCK(mp);
2036
2037 /* disable counter and sync counter */
2038 xfs_icsb_disable_counter(mp, field);
2039
2040 /* update counters - first CPU gets residual*/
2041 switch (field) {
2042 case XFS_SBS_ICOUNT:
2043 count = mp->m_sb.sb_icount;
2044 resid = do_div(count, weight);
2045 if (count < XFS_ICSB_INO_CNTR_REENABLE)
2046 goto out;
2047 break;
2048 case XFS_SBS_IFREE:
2049 count = mp->m_sb.sb_ifree;
2050 resid = do_div(count, weight);
2051 if (count < XFS_ICSB_INO_CNTR_REENABLE)
2052 goto out;
2053 break;
2054 case XFS_SBS_FDBLOCKS:
2055 count = mp->m_sb.sb_fdblocks;
2056 resid = do_div(count, weight);
2057 if (count < XFS_ICSB_FDBLK_CNTR_REENABLE)
2058 goto out;
2059 break;
2060 default:
2061 BUG();
2062 break;
2063 }
2064
2065 xfs_icsb_enable_counter(mp, field, count, resid);
2066out:
2067 if (!(flags & XFS_ICSB_SB_LOCKED))
2068 XFS_SB_UNLOCK(mp, s);
2069}
2070
2071STATIC int
2072xfs_icsb_modify_counters_int(
2073 xfs_mount_t *mp,
2074 xfs_sb_field_t field,
2075 int delta,
2076 int rsvd,
2077 int flags)
2078{
2079 xfs_icsb_cnts_t *icsbp;
2080 long long lcounter; /* long counter for 64 bit fields */
2081 int cpu, s, locked = 0;
2082 int ret = 0, balance_done = 0;
2083
2084again:
2085 cpu = get_cpu();
2086 icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu),
2087 xfs_icsb_lock_cntr(icsbp);
2088 if (unlikely(xfs_icsb_counter_disabled(mp, field)))
2089 goto slow_path;
2090
2091 switch (field) {
2092 case XFS_SBS_ICOUNT:
2093 lcounter = icsbp->icsb_icount;
2094 lcounter += delta;
2095 if (unlikely(lcounter < 0))
2096 goto slow_path;
2097 icsbp->icsb_icount = lcounter;
2098 break;
2099
2100 case XFS_SBS_IFREE:
2101 lcounter = icsbp->icsb_ifree;
2102 lcounter += delta;
2103 if (unlikely(lcounter < 0))
2104 goto slow_path;
2105 icsbp->icsb_ifree = lcounter;
2106 break;
2107
2108 case XFS_SBS_FDBLOCKS:
2109 BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0);
2110
2111 lcounter = icsbp->icsb_fdblocks;
2112 lcounter += delta;
2113 if (unlikely(lcounter < 0))
2114 goto slow_path;
2115 icsbp->icsb_fdblocks = lcounter;
2116 break;
2117 default:
2118 BUG();
2119 break;
2120 }
2121 xfs_icsb_unlock_cntr(icsbp);
2122 put_cpu();
2123 if (locked)
2124 XFS_SB_UNLOCK(mp, s);
2125 return 0;
2126
2127 /*
2128 * The slow path needs to be run with the SBLOCK
2129 * held so that we prevent other threads from
2130 * attempting to run this path at the same time.
2131 * this provides exclusion for the balancing code,
2132 * and exclusive fallback if the balance does not
2133 * provide enough resources to continue in an unlocked
2134 * manner.
2135 */
2136slow_path:
2137 xfs_icsb_unlock_cntr(icsbp);
2138 put_cpu();
2139
2140 /* need to hold superblock incase we need
2141 * to disable a counter */
2142 if (!(flags & XFS_ICSB_SB_LOCKED)) {
2143 s = XFS_SB_LOCK(mp);
2144 locked = 1;
2145 flags |= XFS_ICSB_SB_LOCKED;
2146 }
2147 if (!balance_done) {
2148 xfs_icsb_balance_counter(mp, field, flags);
2149 balance_done = 1;
2150 goto again;
2151 } else {
2152 /*
2153 * we might not have enough on this local
2154 * cpu to allocate for a bulk request.
2155 * We need to drain this field from all CPUs
2156 * and disable the counter fastpath
2157 */
2158 xfs_icsb_disable_counter(mp, field);
2159 }
2160
2161 ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
2162
2163 if (locked)
2164 XFS_SB_UNLOCK(mp, s);
2165 return ret;
2166}
2167
2168STATIC int
2169xfs_icsb_modify_counters(
2170 xfs_mount_t *mp,
2171 xfs_sb_field_t field,
2172 int delta,
2173 int rsvd)
2174{
2175 return xfs_icsb_modify_counters_int(mp, field, delta, rsvd, 0);
2176}
2177
2178/*
2179 * Called when superblock is already locked
2180 */
2181STATIC int
2182xfs_icsb_modify_counters_locked(
2183 xfs_mount_t *mp,
2184 xfs_sb_field_t field,
2185 int delta,
2186 int rsvd)
2187{
2188 return xfs_icsb_modify_counters_int(mp, field, delta,
2189 rsvd, XFS_ICSB_SB_LOCKED);
2190}
2191#endif