aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2015-02-23 05:22:03 -0500
committerDave Chinner <david@fromorbit.com>2015-02-23 05:22:03 -0500
commit0d485ada404b3614b045e574bec26aaf5d9b3c5b (patch)
treeb08812daee1eed9e8be59e6c12bf0eeef5b6f7cf /fs
parente88b64ea1f3da64dbb52636377be295c90367377 (diff)
xfs: use generic percpu counters for free block counter
XFS has hand-rolled per-cpu counters for the superblock since before there was any generic implementation. The free block counter is special in that it is used for ENOSPC detection outside transaction contexts for for delayed allocation. This means that the counter needs to be accurate at zero. The current per-cpu counter code jumps through lots of hoops to ensure we never run past zero, but we don't need to make all those jumps with the generic counter implementation. The generic counter implementation allows us to pass a "batch" threshold at which the addition/subtraction to the counter value will be folded back into global value under lock. We can use this feature to reduce the batch size as we approach 0 in a very similar manner to the existing counters and their rebalance algorithm. If we use a batch size of 1 as we approach 0, then every addition and subtraction will be done against the global value and hence allow accurate detection of zero threshold crossing. Hence we can replace the handrolled, accurate-at-zero counters with generic percpu counters. Note: this removes just enough of the icsb infrastructure to compile without warnings. The rest will go in subsequent commits. 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')
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c32
-rw-r--r--fs/xfs/libxfs/xfs_sb.c1
-rw-r--r--fs/xfs/xfs_fsops.c9
-rw-r--r--fs/xfs/xfs_iomap.c2
-rw-r--r--fs/xfs/xfs_mount.c192
-rw-r--r--fs/xfs/xfs_mount.h3
-rw-r--r--fs/xfs/xfs_super.c10
-rw-r--r--fs/xfs/xfs_trans.c16
8 files changed, 134 insertions, 131 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 61ec015dca16..e39c9e83670e 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -2212,9 +2212,8 @@ xfs_bmap_add_extent_delay_real(
2212 diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) - 2212 diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
2213 (bma->cur ? bma->cur->bc_private.b.allocated : 0)); 2213 (bma->cur ? bma->cur->bc_private.b.allocated : 0));
2214 if (diff > 0) { 2214 if (diff > 0) {
2215 error = xfs_icsb_modify_counters(bma->ip->i_mount, 2215 error = xfs_mod_fdblocks(bma->ip->i_mount,
2216 XFS_SBS_FDBLOCKS, 2216 -((int64_t)diff), false);
2217 -((int64_t)diff), 0);
2218 ASSERT(!error); 2217 ASSERT(!error);
2219 if (error) 2218 if (error)
2220 goto done; 2219 goto done;
@@ -2265,9 +2264,8 @@ xfs_bmap_add_extent_delay_real(
2265 temp += bma->cur->bc_private.b.allocated; 2264 temp += bma->cur->bc_private.b.allocated;
2266 ASSERT(temp <= da_old); 2265 ASSERT(temp <= da_old);
2267 if (temp < da_old) 2266 if (temp < da_old)
2268 xfs_icsb_modify_counters(bma->ip->i_mount, 2267 xfs_mod_fdblocks(bma->ip->i_mount,
2269 XFS_SBS_FDBLOCKS, 2268 (int64_t)(da_old - temp), false);
2270 (int64_t)(da_old - temp), 0);
2271 } 2269 }
2272 2270
2273 /* clear out the allocated field, done with it now in any case. */ 2271 /* clear out the allocated field, done with it now in any case. */
@@ -2944,8 +2942,8 @@ xfs_bmap_add_extent_hole_delay(
2944 } 2942 }
2945 if (oldlen != newlen) { 2943 if (oldlen != newlen) {
2946 ASSERT(oldlen > newlen); 2944 ASSERT(oldlen > newlen);
2947 xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS, 2945 xfs_mod_fdblocks(ip->i_mount, (int64_t)(oldlen - newlen),
2948 (int64_t)(oldlen - newlen), 0); 2946 false);
2949 /* 2947 /*
2950 * Nothing to do for disk quota accounting here. 2948 * Nothing to do for disk quota accounting here.
2951 */ 2949 */
@@ -4163,15 +4161,13 @@ xfs_bmapi_reserve_delalloc(
4163 error = xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, 4161 error = xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
4164 -((int64_t)extsz), 0); 4162 -((int64_t)extsz), 0);
4165 } else { 4163 } else {
4166 error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 4164 error = xfs_mod_fdblocks(mp, -((int64_t)alen), false);
4167 -((int64_t)alen), 0);
4168 } 4165 }
4169 4166
4170 if (error) 4167 if (error)
4171 goto out_unreserve_quota; 4168 goto out_unreserve_quota;
4172 4169
4173 error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 4170 error = xfs_mod_fdblocks(mp, -((int64_t)indlen), false);
4174 -((int64_t)indlen), 0);
4175 if (error) 4171 if (error)
4176 goto out_unreserve_blocks; 4172 goto out_unreserve_blocks;
4177 4173
@@ -4200,7 +4196,7 @@ out_unreserve_blocks:
4200 if (rt) 4196 if (rt)
4201 xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, extsz, 0); 4197 xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, extsz, 0);
4202 else 4198 else
4203 xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, alen, 0); 4199 xfs_mod_fdblocks(mp, alen, false);
4204out_unreserve_quota: 4200out_unreserve_quota:
4205 if (XFS_IS_QUOTA_ON(mp)) 4201 if (XFS_IS_QUOTA_ON(mp))
4206 xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0, rt ? 4202 xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0, rt ?
@@ -5012,10 +5008,8 @@ xfs_bmap_del_extent(
5012 * Nothing to do for disk quota accounting here. 5008 * Nothing to do for disk quota accounting here.
5013 */ 5009 */
5014 ASSERT(da_old >= da_new); 5010 ASSERT(da_old >= da_new);
5015 if (da_old > da_new) { 5011 if (da_old > da_new)
5016 xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 5012 xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false);
5017 (int64_t)(da_old - da_new), 0);
5018 }
5019done: 5013done:
5020 *logflagsp = flags; 5014 *logflagsp = flags;
5021 return error; 5015 return error;
@@ -5290,8 +5284,8 @@ xfs_bunmapi(
5290 ip, -((long)del.br_blockcount), 0, 5284 ip, -((long)del.br_blockcount), 0,
5291 XFS_QMOPT_RES_RTBLKS); 5285 XFS_QMOPT_RES_RTBLKS);
5292 } else { 5286 } else {
5293 xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 5287 xfs_mod_fdblocks(mp, (int64_t)del.br_blockcount,
5294 (int64_t)del.br_blockcount, 0); 5288 false);
5295 (void)xfs_trans_reserve_quota_nblks(NULL, 5289 (void)xfs_trans_reserve_quota_nblks(NULL,
5296 ip, -((long)del.br_blockcount), 0, 5290 ip, -((long)del.br_blockcount), 0,
5297 XFS_QMOPT_RES_REGBLKS); 5291 XFS_QMOPT_RES_REGBLKS);
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index b66aeab99cfb..31a3e972f86f 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -773,6 +773,7 @@ xfs_log_sb(
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 mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree);
776 mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks);
776 777
777 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); 778 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb);
778 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); 779 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 a1ca9c2b8c00..7ef25588062f 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -640,9 +640,10 @@ xfs_fs_counts(
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 cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
643 cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
644 XFS_ALLOC_SET_ASIDE(mp);
643 645
644 spin_lock(&mp->m_sb_lock); 646 spin_lock(&mp->m_sb_lock);
645 cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
646 cnt->freertx = mp->m_sb.sb_frextents; 647 cnt->freertx = mp->m_sb.sb_frextents;
647 spin_unlock(&mp->m_sb_lock); 648 spin_unlock(&mp->m_sb_lock);
648 return 0; 649 return 0;
@@ -717,7 +718,8 @@ retry:
717 } else { 718 } else {
718 __int64_t free; 719 __int64_t free;
719 720
720 free = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); 721 free = percpu_counter_sum(&mp->m_fdblocks) -
722 XFS_ALLOC_SET_ASIDE(mp);
721 if (!free) 723 if (!free)
722 goto out; /* ENOSPC and fdblks_delta = 0 */ 724 goto out; /* ENOSPC and fdblks_delta = 0 */
723 725
@@ -756,8 +758,7 @@ out:
756 * the extra reserve blocks from the reserve..... 758 * the extra reserve blocks from the reserve.....
757 */ 759 */
758 int error; 760 int error;
759 error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 761 error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
760 fdblks_delta, 0);
761 if (error == -ENOSPC) 762 if (error == -ENOSPC)
762 goto retry; 763 goto retry;
763 } 764 }
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index ccb1dd0d509e..205b948c9d20 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -461,7 +461,7 @@ xfs_iomap_prealloc_size(
461 alloc_blocks); 461 alloc_blocks);
462 462
463 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); 463 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
464 freesp = mp->m_sb.sb_fdblocks; 464 freesp = percpu_counter_read_positive(&mp->m_fdblocks);
465 if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) { 465 if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) {
466 shift = 2; 466 shift = 2;
467 if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT]) 467 if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT])
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 650e8f18cd2a..767c09a5d3ff 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1114,7 +1114,6 @@ xfs_mod_icount(
1114 return 0; 1114 return 0;
1115} 1115}
1116 1116
1117
1118int 1117int
1119xfs_mod_ifree( 1118xfs_mod_ifree(
1120 struct xfs_mount *mp, 1119 struct xfs_mount *mp,
@@ -1128,6 +1127,92 @@ xfs_mod_ifree(
1128 } 1127 }
1129 return 0; 1128 return 0;
1130} 1129}
1130
1131int
1132xfs_mod_fdblocks(
1133 struct xfs_mount *mp,
1134 int64_t delta,
1135 bool rsvd)
1136{
1137 int64_t lcounter;
1138 long long res_used;
1139 s32 batch;
1140
1141 if (delta > 0) {
1142 /*
1143 * If the reserve pool is depleted, put blocks back into it
1144 * first. Most of the time the pool is full.
1145 */
1146 if (likely(mp->m_resblks == mp->m_resblks_avail)) {
1147 percpu_counter_add(&mp->m_fdblocks, delta);
1148 return 0;
1149 }
1150
1151 spin_lock(&mp->m_sb_lock);
1152 res_used = (long long)(mp->m_resblks - mp->m_resblks_avail);
1153
1154 if (res_used > delta) {
1155 mp->m_resblks_avail += delta;
1156 } else {
1157 delta -= res_used;
1158 mp->m_resblks_avail = mp->m_resblks;
1159 percpu_counter_add(&mp->m_fdblocks, delta);
1160 }
1161 spin_unlock(&mp->m_sb_lock);
1162 return 0;
1163 }
1164
1165 /*
1166 * Taking blocks away, need to be more accurate the closer we
1167 * are to zero.
1168 *
1169 * batch size is set to a maximum of 1024 blocks - if we are
1170 * allocating of freeing extents larger than this then we aren't
1171 * going to be hammering the counter lock so a lock per update
1172 * is not a problem.
1173 *
1174 * If the counter has a value of less than 2 * max batch size,
1175 * then make everything serialise as we are real close to
1176 * ENOSPC.
1177 */
1178#define __BATCH 1024
1179 if (percpu_counter_compare(&mp->m_fdblocks, 2 * __BATCH) < 0)
1180 batch = 1;
1181 else
1182 batch = __BATCH;
1183#undef __BATCH
1184
1185 __percpu_counter_add(&mp->m_fdblocks, delta, batch);
1186 if (percpu_counter_compare(&mp->m_fdblocks,
1187 XFS_ALLOC_SET_ASIDE(mp)) >= 0) {
1188 /* we had space! */
1189 return 0;
1190 }
1191
1192 /*
1193 * lock up the sb for dipping into reserves before releasing the space
1194 * that took us to ENOSPC.
1195 */
1196 spin_lock(&mp->m_sb_lock);
1197 percpu_counter_add(&mp->m_fdblocks, -delta);
1198 if (!rsvd)
1199 goto fdblocks_enospc;
1200
1201 lcounter = (long long)mp->m_resblks_avail + delta;
1202 if (lcounter >= 0) {
1203 mp->m_resblks_avail = lcounter;
1204 spin_unlock(&mp->m_sb_lock);
1205 return 0;
1206 }
1207 printk_once(KERN_WARNING
1208 "Filesystem \"%s\": reserve blocks depleted! "
1209 "Consider increasing reserve pool size.",
1210 mp->m_fsname);
1211fdblocks_enospc:
1212 spin_unlock(&mp->m_sb_lock);
1213 return -ENOSPC;
1214}
1215
1131/* 1216/*
1132 * xfs_mod_incore_sb_unlocked() is a utility routine commonly used to apply 1217 * xfs_mod_incore_sb_unlocked() is a utility routine commonly used to apply
1133 * a delta to a specified field in the in-core superblock. Simply 1218 * a delta to a specified field in the in-core superblock. Simply
@@ -1146,7 +1231,6 @@ xfs_mod_incore_sb_unlocked(
1146{ 1231{
1147 int scounter; /* short counter for 32 bit fields */ 1232 int scounter; /* short counter for 32 bit fields */
1148 long long lcounter; /* long counter for 64 bit fields */ 1233 long long lcounter; /* long counter for 64 bit fields */
1149 long long res_used, rem;
1150 1234
1151 /* 1235 /*
1152 * With the in-core superblock spin lock held, switch 1236 * With the in-core superblock spin lock held, switch
@@ -1157,50 +1241,9 @@ xfs_mod_incore_sb_unlocked(
1157 switch (field) { 1241 switch (field) {
1158 case XFS_SBS_ICOUNT: 1242 case XFS_SBS_ICOUNT:
1159 case XFS_SBS_IFREE: 1243 case XFS_SBS_IFREE:
1244 case XFS_SBS_FDBLOCKS:
1160 ASSERT(0); 1245 ASSERT(0);
1161 return -EINVAL; 1246 return -EINVAL;
1162 case XFS_SBS_FDBLOCKS:
1163 lcounter = (long long)
1164 mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
1165 res_used = (long long)(mp->m_resblks - mp->m_resblks_avail);
1166
1167 if (delta > 0) { /* Putting blocks back */
1168 if (res_used > delta) {
1169 mp->m_resblks_avail += delta;
1170 } else {
1171 rem = delta - res_used;
1172 mp->m_resblks_avail = mp->m_resblks;
1173 lcounter += rem;
1174 }
1175 } else { /* Taking blocks away */
1176 lcounter += delta;
1177 if (lcounter >= 0) {
1178 mp->m_sb.sb_fdblocks = lcounter +
1179 XFS_ALLOC_SET_ASIDE(mp);
1180 return 0;
1181 }
1182
1183 /*
1184 * We are out of blocks, use any available reserved
1185 * blocks if were allowed to.
1186 */
1187 if (!rsvd)
1188 return -ENOSPC;
1189
1190 lcounter = (long long)mp->m_resblks_avail + delta;
1191 if (lcounter >= 0) {
1192 mp->m_resblks_avail = lcounter;
1193 return 0;
1194 }
1195 printk_once(KERN_WARNING
1196 "Filesystem \"%s\": reserve blocks depleted! "
1197 "Consider increasing reserve pool size.",
1198 mp->m_fsname);
1199 return -ENOSPC;
1200 }
1201
1202 mp->m_sb.sb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp);
1203 return 0;
1204 case XFS_SBS_FREXTENTS: 1247 case XFS_SBS_FREXTENTS:
1205 lcounter = (long long)mp->m_sb.sb_frextents; 1248 lcounter = (long long)mp->m_sb.sb_frextents;
1206 lcounter += delta; 1249 lcounter += delta;
@@ -1323,7 +1366,7 @@ xfs_mod_incore_sb(
1323 * 1366 *
1324 * Note that this function may not be used for the superblock values that 1367 * Note that this function may not be used for the superblock values that
1325 * are tracked with the in-memory per-cpu counters - a direct call to 1368 * are tracked with the in-memory per-cpu counters - a direct call to
1326 * xfs_icsb_modify_counters is required for these. 1369 * xfs_mod_incore_sb is required for these.
1327 */ 1370 */
1328int 1371int
1329xfs_mod_incore_sb_batch( 1372xfs_mod_incore_sb_batch(
@@ -1508,7 +1551,6 @@ xfs_icsb_cpu_notify(
1508 case CPU_ONLINE: 1551 case CPU_ONLINE:
1509 case CPU_ONLINE_FROZEN: 1552 case CPU_ONLINE_FROZEN:
1510 xfs_icsb_lock(mp); 1553 xfs_icsb_lock(mp);
1511 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
1512 xfs_icsb_unlock(mp); 1554 xfs_icsb_unlock(mp);
1513 break; 1555 break;
1514 case CPU_DEAD: 1556 case CPU_DEAD:
@@ -1518,13 +1560,9 @@ xfs_icsb_cpu_notify(
1518 * re-enable the counters. */ 1560 * re-enable the counters. */
1519 xfs_icsb_lock(mp); 1561 xfs_icsb_lock(mp);
1520 spin_lock(&mp->m_sb_lock); 1562 spin_lock(&mp->m_sb_lock);
1521 xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS);
1522
1523 mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks;
1524 1563
1525 memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); 1564 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
1526 1565
1527 xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0);
1528 spin_unlock(&mp->m_sb_lock); 1566 spin_unlock(&mp->m_sb_lock);
1529 xfs_icsb_unlock(mp); 1567 xfs_icsb_unlock(mp);
1530 break; 1568 break;
@@ -1550,10 +1588,14 @@ xfs_icsb_init_counters(
1550 if (error) 1588 if (error)
1551 goto free_icount; 1589 goto free_icount;
1552 1590
1591 error = percpu_counter_init(&mp->m_fdblocks, 0, GFP_KERNEL);
1592 if (error)
1593 goto free_ifree;
1594
1553 mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t); 1595 mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t);
1554 if (!mp->m_sb_cnts) { 1596 if (!mp->m_sb_cnts) {
1555 error = -ENOMEM; 1597 error = -ENOMEM;
1556 goto free_ifree; 1598 goto free_fdblocks;
1557 } 1599 }
1558 1600
1559 for_each_online_cpu(i) { 1601 for_each_online_cpu(i) {
@@ -1577,6 +1619,8 @@ xfs_icsb_init_counters(
1577 1619
1578 return 0; 1620 return 0;
1579 1621
1622free_fdblocks:
1623 percpu_counter_destroy(&mp->m_fdblocks);
1580free_ifree: 1624free_ifree:
1581 percpu_counter_destroy(&mp->m_ifree); 1625 percpu_counter_destroy(&mp->m_ifree);
1582free_icount: 1626free_icount:
@@ -1590,6 +1634,7 @@ xfs_icsb_reinit_counters(
1590{ 1634{
1591 percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount); 1635 percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount);
1592 percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree); 1636 percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree);
1637 percpu_counter_set(&mp->m_fdblocks, mp->m_sb.sb_fdblocks);
1593 1638
1594 xfs_icsb_lock(mp); 1639 xfs_icsb_lock(mp);
1595 /* 1640 /*
@@ -1597,7 +1642,6 @@ xfs_icsb_reinit_counters(
1597 * initial balance kicks us off correctly 1642 * initial balance kicks us off correctly
1598 */ 1643 */
1599 mp->m_icsb_counters = -1; 1644 mp->m_icsb_counters = -1;
1600 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
1601 xfs_icsb_unlock(mp); 1645 xfs_icsb_unlock(mp);
1602} 1646}
1603 1647
@@ -1612,6 +1656,7 @@ xfs_icsb_destroy_counters(
1612 1656
1613 percpu_counter_destroy(&mp->m_icount); 1657 percpu_counter_destroy(&mp->m_icount);
1614 percpu_counter_destroy(&mp->m_ifree); 1658 percpu_counter_destroy(&mp->m_ifree);
1659 percpu_counter_destroy(&mp->m_fdblocks);
1615 1660
1616 mutex_destroy(&mp->m_icsb_mutex); 1661 mutex_destroy(&mp->m_icsb_mutex);
1617} 1662}
@@ -1665,18 +1710,11 @@ xfs_icsb_count(
1665 xfs_icsb_cnts_t *cnt, 1710 xfs_icsb_cnts_t *cnt,
1666 int flags) 1711 int flags)
1667{ 1712{
1668 xfs_icsb_cnts_t *cntp;
1669 int i;
1670
1671 memset(cnt, 0, sizeof(xfs_icsb_cnts_t)); 1713 memset(cnt, 0, sizeof(xfs_icsb_cnts_t));
1672 1714
1673 if (!(flags & XFS_ICSB_LAZY_COUNT)) 1715 if (!(flags & XFS_ICSB_LAZY_COUNT))
1674 xfs_icsb_lock_all_counters(mp); 1716 xfs_icsb_lock_all_counters(mp);
1675 1717
1676 for_each_online_cpu(i) {
1677 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
1678 cnt->icsb_fdblocks += cntp->icsb_fdblocks;
1679 }
1680 1718
1681 if (!(flags & XFS_ICSB_LAZY_COUNT)) 1719 if (!(flags & XFS_ICSB_LAZY_COUNT))
1682 xfs_icsb_unlock_all_counters(mp); 1720 xfs_icsb_unlock_all_counters(mp);
@@ -1687,7 +1725,6 @@ xfs_icsb_counter_disabled(
1687 xfs_mount_t *mp, 1725 xfs_mount_t *mp,
1688 xfs_sb_field_t field) 1726 xfs_sb_field_t field)
1689{ 1727{
1690 ASSERT(field == XFS_SBS_FDBLOCKS);
1691 return test_bit(field, &mp->m_icsb_counters); 1728 return test_bit(field, &mp->m_icsb_counters);
1692} 1729}
1693 1730
@@ -1698,8 +1735,6 @@ xfs_icsb_disable_counter(
1698{ 1735{
1699 xfs_icsb_cnts_t cnt; 1736 xfs_icsb_cnts_t cnt;
1700 1737
1701 ASSERT(field == XFS_SBS_FDBLOCKS);
1702
1703 /* 1738 /*
1704 * If we are already disabled, then there is nothing to do 1739 * If we are already disabled, then there is nothing to do
1705 * here. We check before locking all the counters to avoid 1740 * here. We check before locking all the counters to avoid
@@ -1717,9 +1752,6 @@ xfs_icsb_disable_counter(
1717 1752
1718 xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT); 1753 xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT);
1719 switch(field) { 1754 switch(field) {
1720 case XFS_SBS_FDBLOCKS:
1721 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
1722 break;
1723 default: 1755 default:
1724 BUG(); 1756 BUG();
1725 } 1757 }
@@ -1735,18 +1767,11 @@ xfs_icsb_enable_counter(
1735 uint64_t count, 1767 uint64_t count,
1736 uint64_t resid) 1768 uint64_t resid)
1737{ 1769{
1738 xfs_icsb_cnts_t *cntp;
1739 int i; 1770 int i;
1740 1771
1741 ASSERT(field == XFS_SBS_FDBLOCKS);
1742
1743 xfs_icsb_lock_all_counters(mp); 1772 xfs_icsb_lock_all_counters(mp);
1744 for_each_online_cpu(i) { 1773 for_each_online_cpu(i) {
1745 cntp = per_cpu_ptr(mp->m_sb_cnts, i);
1746 switch (field) { 1774 switch (field) {
1747 case XFS_SBS_FDBLOCKS:
1748 cntp->icsb_fdblocks = count + resid;
1749 break;
1750 default: 1775 default:
1751 BUG(); 1776 BUG();
1752 break; 1777 break;
@@ -1765,9 +1790,6 @@ xfs_icsb_sync_counters_locked(
1765 xfs_icsb_cnts_t cnt; 1790 xfs_icsb_cnts_t cnt;
1766 1791
1767 xfs_icsb_count(mp, &cnt, flags); 1792 xfs_icsb_count(mp, &cnt, flags);
1768
1769 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
1770 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
1771} 1793}
1772 1794
1773/* 1795/*
@@ -1809,20 +1831,12 @@ xfs_icsb_balance_counter_locked(
1809 int min_per_cpu) 1831 int min_per_cpu)
1810{ 1832{
1811 uint64_t count, resid; 1833 uint64_t count, resid;
1812 int weight = num_online_cpus();
1813 uint64_t min = (uint64_t)min_per_cpu;
1814 1834
1815 /* disable counter and sync counter */ 1835 /* disable counter and sync counter */
1816 xfs_icsb_disable_counter(mp, field); 1836 xfs_icsb_disable_counter(mp, field);
1817 1837
1818 /* update counters - first CPU gets residual*/ 1838 /* update counters - first CPU gets residual*/
1819 switch (field) { 1839 switch (field) {
1820 case XFS_SBS_FDBLOCKS:
1821 count = mp->m_sb.sb_fdblocks;
1822 resid = do_div(count, weight);
1823 if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp)))
1824 return;
1825 break;
1826 default: 1840 default:
1827 BUG(); 1841 BUG();
1828 count = resid = 0; /* quiet, gcc */ 1842 count = resid = 0; /* quiet, gcc */
@@ -1851,7 +1865,6 @@ xfs_icsb_modify_counters(
1851 int rsvd) 1865 int rsvd)
1852{ 1866{
1853 xfs_icsb_cnts_t *icsbp; 1867 xfs_icsb_cnts_t *icsbp;
1854 long long lcounter; /* long counter for 64 bit fields */
1855 int ret = 0; 1868 int ret = 0;
1856 1869
1857 might_sleep(); 1870 might_sleep();
@@ -1871,18 +1884,9 @@ again:
1871 } 1884 }
1872 1885
1873 switch (field) { 1886 switch (field) {
1874 case XFS_SBS_FDBLOCKS:
1875 BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0);
1876
1877 lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
1878 lcounter += delta;
1879 if (unlikely(lcounter < 0))
1880 goto balance_counter;
1881 icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp);
1882 break;
1883 default: 1887 default:
1884 BUG(); 1888 BUG();
1885 break; 1889 goto balance_counter; /* be still, gcc */
1886 } 1890 }
1887 xfs_icsb_unlock_cntr(icsbp); 1891 xfs_icsb_unlock_cntr(icsbp);
1888 preempt_enable(); 1892 preempt_enable();
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 7ce997d43d81..84b745fbc787 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -85,6 +85,7 @@ typedef struct xfs_mount {
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 struct percpu_counter m_ifree; /* free inodes counter */
88 struct percpu_counter m_fdblocks; /* free block counter */
88 89
89 struct xfs_buf *m_sb_bp; /* buffer for superblock */ 90 struct xfs_buf *m_sb_bp; /* buffer for superblock */
90 char *m_fsname; /* filesystem name */ 91 char *m_fsname; /* filesystem name */
@@ -393,6 +394,8 @@ extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
393 uint, int); 394 uint, int);
394extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta); 395extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta);
395extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta); 396extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta);
397extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
398 bool reserved);
396extern int xfs_mount_log_sb(xfs_mount_t *); 399extern int xfs_mount_log_sb(xfs_mount_t *);
397extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); 400extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
398extern int xfs_readsb(xfs_mount_t *, int); 401extern int xfs_readsb(xfs_mount_t *, int);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 049147776ee1..9ec75074026d 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1087,6 +1087,7 @@ xfs_fs_statfs(
1087 __uint64_t fakeinos, id; 1087 __uint64_t fakeinos, id;
1088 __uint64_t icount; 1088 __uint64_t icount;
1089 __uint64_t ifree; 1089 __uint64_t ifree;
1090 __uint64_t fdblocks;
1090 xfs_extlen_t lsize; 1091 xfs_extlen_t lsize;
1091 __int64_t ffree; 1092 __int64_t ffree;
1092 1093
@@ -1100,13 +1101,17 @@ xfs_fs_statfs(
1100 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); 1101 xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
1101 icount = percpu_counter_sum(&mp->m_icount); 1102 icount = percpu_counter_sum(&mp->m_icount);
1102 ifree = percpu_counter_sum(&mp->m_ifree); 1103 ifree = percpu_counter_sum(&mp->m_ifree);
1104 fdblocks = percpu_counter_sum(&mp->m_fdblocks);
1103 1105
1104 spin_lock(&mp->m_sb_lock); 1106 spin_lock(&mp->m_sb_lock);
1105 statp->f_bsize = sbp->sb_blocksize; 1107 statp->f_bsize = sbp->sb_blocksize;
1106 lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; 1108 lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0;
1107 statp->f_blocks = sbp->sb_dblocks - lsize; 1109 statp->f_blocks = sbp->sb_dblocks - lsize;
1108 statp->f_bfree = statp->f_bavail = 1110 spin_unlock(&mp->m_sb_lock);
1109 sbp->sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); 1111
1112 statp->f_bfree = fdblocks - XFS_ALLOC_SET_ASIDE(mp);
1113 statp->f_bavail = statp->f_bfree;
1114
1110 fakeinos = statp->f_bfree << sbp->sb_inopblog; 1115 fakeinos = statp->f_bfree << sbp->sb_inopblog;
1111 statp->f_files = MIN(icount + fakeinos, (__uint64_t)XFS_MAXINUMBER); 1116 statp->f_files = MIN(icount + fakeinos, (__uint64_t)XFS_MAXINUMBER);
1112 if (mp->m_maxicount) 1117 if (mp->m_maxicount)
@@ -1123,7 +1128,6 @@ xfs_fs_statfs(
1123 ffree = statp->f_files - (icount - ifree); 1128 ffree = statp->f_files - (icount - ifree);
1124 statp->f_ffree = max_t(__int64_t, ffree, 0); 1129 statp->f_ffree = max_t(__int64_t, ffree, 0);
1125 1130
1126 spin_unlock(&mp->m_sb_lock);
1127 1131
1128 if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && 1132 if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
1129 ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) == 1133 ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 68680ce67547..e99f5e552c64 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -173,7 +173,7 @@ xfs_trans_reserve(
173 uint rtextents) 173 uint rtextents)
174{ 174{
175 int error = 0; 175 int error = 0;
176 int rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; 176 bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
177 177
178 /* Mark this thread as being in a transaction */ 178 /* Mark this thread as being in a transaction */
179 current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); 179 current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
@@ -184,8 +184,7 @@ xfs_trans_reserve(
184 * fail if the count would go below zero. 184 * fail if the count would go below zero.
185 */ 185 */
186 if (blocks > 0) { 186 if (blocks > 0) {
187 error = xfs_icsb_modify_counters(tp->t_mountp, XFS_SBS_FDBLOCKS, 187 error = xfs_mod_fdblocks(tp->t_mountp, -((int64_t)blocks), rsvd);
188 -((int64_t)blocks), rsvd);
189 if (error != 0) { 188 if (error != 0) {
190 current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 189 current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
191 return -ENOSPC; 190 return -ENOSPC;
@@ -268,8 +267,7 @@ undo_log:
268 267
269undo_blocks: 268undo_blocks:
270 if (blocks > 0) { 269 if (blocks > 0) {
271 xfs_icsb_modify_counters(tp->t_mountp, XFS_SBS_FDBLOCKS, 270 xfs_mod_fdblocks(tp->t_mountp, -((int64_t)blocks), rsvd);
272 (int64_t)blocks, rsvd);
273 tp->t_blk_res = 0; 271 tp->t_blk_res = 0;
274 } 272 }
275 273
@@ -516,14 +514,13 @@ xfs_trans_unreserve_and_mod_sb(
516 xfs_mount_t *mp = tp->t_mountp; 514 xfs_mount_t *mp = tp->t_mountp;
517 /* REFERENCED */ 515 /* REFERENCED */
518 int error; 516 int error;
519 int rsvd; 517 bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
520 int64_t blkdelta = 0; 518 int64_t blkdelta = 0;
521 int64_t rtxdelta = 0; 519 int64_t rtxdelta = 0;
522 int64_t idelta = 0; 520 int64_t idelta = 0;
523 int64_t ifreedelta = 0; 521 int64_t ifreedelta = 0;
524 522
525 msbp = msb; 523 msbp = msb;
526 rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
527 524
528 /* calculate deltas */ 525 /* calculate deltas */
529 if (tp->t_blk_res > 0) 526 if (tp->t_blk_res > 0)
@@ -547,8 +544,7 @@ xfs_trans_unreserve_and_mod_sb(
547 544
548 /* apply the per-cpu counters */ 545 /* apply the per-cpu counters */
549 if (blkdelta) { 546 if (blkdelta) {
550 error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 547 error = xfs_mod_fdblocks(mp, blkdelta, rsvd);
551 blkdelta, rsvd);
552 if (error) 548 if (error)
553 goto out; 549 goto out;
554 } 550 }
@@ -635,7 +631,7 @@ out_undo_icount:
635 xfs_mod_icount(mp, -idelta); 631 xfs_mod_icount(mp, -idelta);
636out_undo_fdblocks: 632out_undo_fdblocks:
637 if (blkdelta) 633 if (blkdelta)
638 xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, -blkdelta, rsvd); 634 xfs_mod_fdblocks(mp, -blkdelta, rsvd);
639out: 635out:
640 ASSERT(error == 0); 636 ASSERT(error == 0);
641 return; 637 return;