#include "xfs_fsops.h"
#include "xfs_utils.h"
-STATIC void xfs_mount_log_sb(xfs_mount_t *, __int64_t);
+STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
STATIC int xfs_uuid_mount(xfs_mount_t *);
STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
STATIC void xfs_unmountfs_wait(xfs_mount_t *);
#ifdef HAVE_PERCPU_SB
STATIC void xfs_icsb_destroy_counters(xfs_mount_t *);
STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
- int, int);
-STATIC void xfs_icsb_sync_counters(xfs_mount_t *);
+ int);
+STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t,
+ int);
STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
int64_t, int);
STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
#else
#define xfs_icsb_destroy_counters(mp) do { } while (0)
-#define xfs_icsb_balance_counter(mp, a, b, c) do { } while (0)
-#define xfs_icsb_sync_counters(mp) do { } while (0)
+#define xfs_icsb_balance_counter(mp, a, b) do { } while (0)
+#define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0)
#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)
#endif
/*
* If fs is not mounted readonly, then update the superblock changes.
*/
- if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY))
- xfs_mount_log_sb(mp, update_flags);
+ if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
+ error = xfs_mount_log_sb(mp, update_flags);
+ if (error) {
+ cmn_err(CE_WARN, "XFS: failed to write sb changes");
+ goto error4;
+ }
+ }
/*
* Initialise the XFS quota management subsystem for this mount
cmn_err(CE_WARN, "XFS: Unable to free reserved block pool. "
"Freespace may not be correct on next mount.");
-
- xfs_log_sbcount(mp, 1);
+ error = xfs_log_sbcount(mp, 1);
+ if (error)
+ cmn_err(CE_WARN, "XFS: Unable to update superblock counters. "
+ "Freespace may not be correct on next mount.");
xfs_unmountfs_writesb(mp);
xfs_unmountfs_wait(mp); /* wait for async bufs */
xfs_log_unmount(mp); /* Done! No more fs ops. */
if (!xfs_fs_writable(mp))
return 0;
- xfs_icsb_sync_counters(mp);
+ xfs_icsb_sync_counters(mp, 0);
/*
* we don't need to do this if we are updating the superblock
xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);
if (sync)
xfs_trans_set_sync(tp);
- xfs_trans_commit(tp, 0);
-
- return 0;
+ error = xfs_trans_commit(tp, 0);
+ return error;
}
STATIC void
XFS_BUF_UNASYNC(sbp);
ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);
xfsbdstrat(mp, sbp);
- /* Nevermind errors we might get here. */
error = xfs_iowait(sbp);
if (error)
xfs_ioerror_alert("xfs_unmountfs_writesb",
* be altered by the mount options, as well as any potential sb_features2
* fixup. Only the first superblock is updated.
*/
-STATIC void
+STATIC int
xfs_mount_log_sb(
xfs_mount_t *mp,
__int64_t fields)
{
xfs_trans_t *tp;
+ int error;
ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2));
tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
- if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
- XFS_DEFAULT_LOG_COUNT)) {
+ error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+ XFS_DEFAULT_LOG_COUNT);
+ if (error) {
xfs_trans_cancel(tp, 0);
- return;
+ return error;
}
xfs_mod_sb(tp, fields);
- xfs_trans_commit(tp, 0);
+ error = xfs_trans_commit(tp, 0);
+ return error;
}
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
xfs_icsb_lock(mp);
- xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
xfs_icsb_unlock(mp);
break;
case CPU_DEAD:
memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
- xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT,
- XFS_ICSB_SB_LOCKED, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_IFREE,
- XFS_ICSB_SB_LOCKED, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS,
- XFS_ICSB_SB_LOCKED, 0);
+ xfs_icsb_balance_counter_locked(mp, XFS_SBS_ICOUNT, 0);
+ xfs_icsb_balance_counter_locked(mp, XFS_SBS_IFREE, 0);
+ xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0);
spin_unlock(&mp->m_sb_lock);
xfs_icsb_unlock(mp);
break;
* initial balance kicks us off correctly
*/
mp->m_icsb_counters = -1;
- xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
xfs_icsb_unlock(mp);
}
if (!test_and_set_bit(field, &mp->m_icsb_counters)) {
/* drain back to superblock */
- xfs_icsb_count(mp, &cnt, XFS_ICSB_SB_LOCKED|XFS_ICSB_LAZY_COUNT);
+ xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT);
switch(field) {
case XFS_SBS_ICOUNT:
mp->m_sb.sb_icount = cnt.icsb_icount;
}
void
-xfs_icsb_sync_counters_flags(
+xfs_icsb_sync_counters_locked(
xfs_mount_t *mp,
int flags)
{
xfs_icsb_cnts_t cnt;
- /* Pass 1: lock all counters */
- if ((flags & XFS_ICSB_SB_LOCKED) == 0)
- spin_lock(&mp->m_sb_lock);
-
xfs_icsb_count(mp, &cnt, flags);
- /* Step 3: update mp->m_sb fields */
if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT))
mp->m_sb.sb_icount = cnt.icsb_icount;
if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE))
mp->m_sb.sb_ifree = cnt.icsb_ifree;
if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
-
- if ((flags & XFS_ICSB_SB_LOCKED) == 0)
- spin_unlock(&mp->m_sb_lock);
}
/*
* Accurate update of per-cpu counters to incore superblock
*/
-STATIC void
+void
xfs_icsb_sync_counters(
- xfs_mount_t *mp)
+ xfs_mount_t *mp,
+ int flags)
{
- xfs_icsb_sync_counters_flags(mp, 0);
+ spin_lock(&mp->m_sb_lock);
+ xfs_icsb_sync_counters_locked(mp, flags);
+ spin_unlock(&mp->m_sb_lock);
}
/*
#define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \
(uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp))
STATIC void
-xfs_icsb_balance_counter(
+xfs_icsb_balance_counter_locked(
xfs_mount_t *mp,
xfs_sb_field_t field,
- int flags,
int min_per_cpu)
{
uint64_t count, resid;
int weight = num_online_cpus();
uint64_t min = (uint64_t)min_per_cpu;
- if (!(flags & XFS_ICSB_SB_LOCKED))
- spin_lock(&mp->m_sb_lock);
-
/* disable counter and sync counter */
xfs_icsb_disable_counter(mp, field);
count = mp->m_sb.sb_icount;
resid = do_div(count, weight);
if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
- goto out;
+ return;
break;
case XFS_SBS_IFREE:
count = mp->m_sb.sb_ifree;
resid = do_div(count, weight);
if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
- goto out;
+ return;
break;
case XFS_SBS_FDBLOCKS:
count = mp->m_sb.sb_fdblocks;
resid = do_div(count, weight);
if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp)))
- goto out;
+ return;
break;
default:
BUG();
}
xfs_icsb_enable_counter(mp, field, count, resid);
-out:
- if (!(flags & XFS_ICSB_SB_LOCKED))
- spin_unlock(&mp->m_sb_lock);
+}
+
+STATIC void
+xfs_icsb_balance_counter(
+ xfs_mount_t *mp,
+ xfs_sb_field_t fields,
+ int min_per_cpu)
+{
+ spin_lock(&mp->m_sb_lock);
+ xfs_icsb_balance_counter_locked(mp, fields, min_per_cpu);
+ spin_unlock(&mp->m_sb_lock);
}
STATIC int
* we are done.
*/
if (ret != ENOSPC)
- xfs_icsb_balance_counter(mp, field, 0, 0);
+ xfs_icsb_balance_counter(mp, field, 0);
xfs_icsb_unlock(mp);
return ret;
* will either succeed through the fast path or slow path without
* another balance operation being required.
*/
- xfs_icsb_balance_counter(mp, field, 0, delta);
+ xfs_icsb_balance_counter(mp, field, delta);
xfs_icsb_unlock(mp);
goto again;
}