Commit 4d11a402 authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner

xfs: remove bitfield based superblock updates

When we log changes to the superblock, we first have to write them
to the on-disk buffer, and then log that. Right now we have a
complex bitfield based arrangement to only write the modified field
to the buffer before we log it.

This used to be necessary as a performance optimisation because we
logged the superblock buffer in every extent or inode allocation or
freeing, and so performance was extremely important. We haven't done
this for years, however, ever since the lazy superblock counters
pulled the superblock logging out of the transaction commit
fast path.

Hence we have a bunch of complexity that is not necessary that makes
writing the in-core superblock to disk much more complex than it
needs to be. We only need to log the superblock now during
management operations (e.g. during mount, unmount or quota control
operations) so it is not a performance critical path anymore.

As such, remove the complex field based logging mechanism and
replace it with a simple conversion function similar to what we use
for all other on-disk structures.

This means we always log the entirity of the superblock, but again
because we rarely modify the superblock this is not an issue for log
bandwidth or CPU time. Indeed, if we do log the superblock
frequently, delayed logging will minimise the impact of this
overhead.

[Fixed gquota/pquota inode sharing regression noticed by bfoster.]
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 97bf6af1
......@@ -403,7 +403,7 @@ xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp)
if (!xfs_sb_version_hasattr2(&mp->m_sb)) {
xfs_sb_version_addattr2(&mp->m_sb);
spin_unlock(&mp->m_sb_lock);
xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
xfs_mod_sb(tp);
} else
spin_unlock(&mp->m_sb_lock);
}
......
......@@ -1221,22 +1221,20 @@ xfs_bmap_add_attrfork(
goto bmap_cancel;
if (!xfs_sb_version_hasattr(&mp->m_sb) ||
(!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) {
__int64_t sbfields = 0;
bool mod_sb = false;
spin_lock(&mp->m_sb_lock);
if (!xfs_sb_version_hasattr(&mp->m_sb)) {
xfs_sb_version_addattr(&mp->m_sb);
sbfields |= XFS_SB_VERSIONNUM;
mod_sb = true;
}
if (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2) {
xfs_sb_version_addattr2(&mp->m_sb);
sbfields |= (XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
mod_sb = true;
}
if (sbfields) {
spin_unlock(&mp->m_sb_lock);
xfs_mod_sb(tp, sbfields);
} else
spin_unlock(&mp->m_sb_lock);
spin_unlock(&mp->m_sb_lock);
if (mod_sb)
xfs_mod_sb(tp);
}
error = xfs_bmap_finish(&tp, &flist, &committed);
......
This diff is collapsed.
......@@ -27,11 +27,11 @@ extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
extern void xfs_perag_put(struct xfs_perag *pag);
extern int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
extern void xfs_sb_calc_crc(struct xfs_buf *);
extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
extern void xfs_sb_mount_common(struct xfs_mount *, struct xfs_sb *);
extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
extern void xfs_sb_calc_crc(struct xfs_buf *bp);
extern void xfs_mod_sb(struct xfs_trans *tp);
extern void xfs_sb_mount_common(struct xfs_mount *mp, struct xfs_sb *sbp);
extern void xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from);
extern void xfs_sb_to_disk(struct xfs_dsb *to, struct xfs_sb *from);
extern void xfs_sb_quota_from_disk(struct xfs_sb *sbp);
#endif /* __XFS_SB_H__ */
......@@ -541,7 +541,7 @@ xfs_growfs_data_private(
saved_error = error;
continue;
}
xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS);
xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb);
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
......@@ -780,9 +780,7 @@ xfs_fs_log_dummy(
xfs_trans_cancel(tp, 0);
return error;
}
/* log the UUID because it is an unchanging field */
xfs_mod_sb(tp, XFS_SB_UUID);
xfs_mod_sb(tp);
xfs_trans_set_sync(tp);
return xfs_trans_commit(tp, 0);
}
......
......@@ -613,7 +613,7 @@ xfs_mount_reset_sbqflags(
return error;
}
xfs_mod_sb(tp, XFS_SB_QFLAGS);
xfs_mod_sb(tp);
return xfs_trans_commit(tp, 0);
}
......@@ -896,7 +896,7 @@ xfs_mountfs(
* perform the update e.g. for the root filesystem.
*/
if (mp->m_update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
error = xfs_mount_log_sb(mp, mp->m_update_flags);
error = xfs_mount_log_sb(mp);
if (error) {
xfs_warn(mp, "failed to write sb changes");
goto out_rtunmount;
......@@ -1126,7 +1126,7 @@ xfs_log_sbcount(xfs_mount_t *mp)
return error;
}
xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);
xfs_mod_sb(tp);
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp, 0);
return error;
......@@ -1429,15 +1429,10 @@ xfs_freesb(
*/
int
xfs_mount_log_sb(
xfs_mount_t *mp,
__int64_t fields)
struct xfs_mount *mp)
{
xfs_trans_t *tp;
int error;
ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2 |
XFS_SB_VERSIONNUM));
struct xfs_trans *tp;
int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0);
......@@ -1445,9 +1440,8 @@ xfs_mount_log_sb(
xfs_trans_cancel(tp, 0);
return error;
}
xfs_mod_sb(tp, fields);
error = xfs_trans_commit(tp, 0);
return error;
xfs_mod_sb(tp);
return xfs_trans_commit(tp, 0);
}
/*
......
......@@ -378,7 +378,7 @@ extern void xfs_unmountfs(xfs_mount_t *);
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
uint, int);
extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
extern int xfs_mount_log_sb(xfs_mount_t *);
extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
extern int xfs_readsb(xfs_mount_t *, int);
extern void xfs_freesb(xfs_mount_t *);
......
......@@ -714,7 +714,6 @@ STATIC int
xfs_qm_qino_alloc(
xfs_mount_t *mp,
xfs_inode_t **ip,
__int64_t sbfields,
uint flags)
{
xfs_trans_t *tp;
......@@ -777,11 +776,6 @@ xfs_qm_qino_alloc(
spin_lock(&mp->m_sb_lock);
if (flags & XFS_QMOPT_SBVERSION) {
ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
XFS_SB_GQUOTINO | XFS_SB_PQUOTINO | XFS_SB_QFLAGS)) ==
(XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
XFS_SB_QFLAGS));
xfs_sb_version_addquota(&mp->m_sb);
mp->m_sb.sb_uquotino = NULLFSINO;
......@@ -798,7 +792,7 @@ xfs_qm_qino_alloc(
else
mp->m_sb.sb_pquotino = (*ip)->i_ino;
spin_unlock(&mp->m_sb_lock);
xfs_mod_sb(tp, sbfields);
xfs_mod_sb(tp);
if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) {
xfs_alert(mp, "%s failed (error %d)!", __func__, error);
......@@ -1451,7 +1445,7 @@ xfs_qm_mount_quotas(
spin_unlock(&mp->m_sb_lock);
if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
if (xfs_qm_write_sb_changes(mp)) {
/*
* We could only have been turning quotas off.
* We aren't in very good shape actually because
......@@ -1482,7 +1476,6 @@ xfs_qm_init_quotainos(
struct xfs_inode *gip = NULL;
struct xfs_inode *pip = NULL;
int error;
__int64_t sbflags = 0;
uint flags = 0;
ASSERT(mp->m_quotainfo);
......@@ -1517,9 +1510,6 @@ xfs_qm_init_quotainos(
}
} else {
flags |= XFS_QMOPT_SBVERSION;
sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
XFS_SB_QFLAGS);
}
/*
......@@ -1530,7 +1520,6 @@ xfs_qm_init_quotainos(
*/
if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
error = xfs_qm_qino_alloc(mp, &uip,
sbflags | XFS_SB_UQUOTINO,
flags | XFS_QMOPT_UQUOTA);
if (error)
goto error_rele;
......@@ -1539,7 +1528,6 @@ xfs_qm_init_quotainos(
}
if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
error = xfs_qm_qino_alloc(mp, &gip,
sbflags | XFS_SB_GQUOTINO,
flags | XFS_QMOPT_GQUOTA);
if (error)
goto error_rele;
......@@ -1548,7 +1536,6 @@ xfs_qm_init_quotainos(
}
if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
error = xfs_qm_qino_alloc(mp, &pip,
sbflags | XFS_SB_PQUOTINO,
flags | XFS_QMOPT_PQUOTA);
if (error)
goto error_rele;
......@@ -1593,8 +1580,7 @@ xfs_qm_dqfree_one(
*/
int
xfs_qm_write_sb_changes(
xfs_mount_t *mp,
__int64_t flags)
struct xfs_mount *mp)
{
xfs_trans_t *tp;
int error;
......@@ -1606,10 +1592,8 @@ xfs_qm_write_sb_changes(
return error;
}
xfs_mod_sb(tp, flags);
error = xfs_trans_commit(tp, 0);
return error;
xfs_mod_sb(tp);
return xfs_trans_commit(tp, 0);
}
......
......@@ -157,7 +157,7 @@ struct xfs_dquot_acct {
#define XFS_QM_RTBWARNLIMIT 5
extern void xfs_qm_destroy_quotainfo(struct xfs_mount *);
extern int xfs_qm_write_sb_changes(struct xfs_mount *, __int64_t);
extern int xfs_qm_write_sb_changes(struct xfs_mount *);
/* dquot stuff */
extern void xfs_qm_dqpurge_all(struct xfs_mount *, uint);
......
......@@ -92,8 +92,7 @@ xfs_qm_scall_quotaoff(
mutex_unlock(&q->qi_quotaofflock);
/* XXX what to do if error ? Revert back to old vals incore ? */
error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
return error;
return xfs_qm_write_sb_changes(mp);
}
dqtype = 0;
......@@ -314,7 +313,6 @@ xfs_qm_scall_quotaon(
{
int error;
uint qf;
__int64_t sbflags;
flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
/*
......@@ -322,8 +320,6 @@ xfs_qm_scall_quotaon(
*/
flags &= ~(XFS_ALL_QUOTA_ACCT);
sbflags = 0;
if (flags == 0) {
xfs_debug(mp, "%s: zero flags, m_qflags=%x",
__func__, mp->m_qflags);
......@@ -370,11 +366,10 @@ xfs_qm_scall_quotaon(
/*
* There's nothing to change if it's the same.
*/
if ((qf & flags) == flags && sbflags == 0)
if ((qf & flags) == flags)
return -EEXIST;
sbflags |= XFS_SB_QFLAGS;
if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
if ((error = xfs_qm_write_sb_changes(mp)))
return error;
/*
* If we aren't trying to switch on quota enforcement, we are done.
......@@ -801,7 +796,7 @@ xfs_qm_log_quotaoff(
mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
spin_unlock(&mp->m_sb_lock);
xfs_mod_sb(tp, XFS_SB_QFLAGS);
xfs_mod_sb(tp);
/*
* We have to make sure that the transaction is secure on disk before we
......
......@@ -1258,7 +1258,7 @@ xfs_fs_remount(
* might have some superblock changes to update.
*/
if (mp->m_update_flags) {
error = xfs_mount_log_sb(mp, mp->m_update_flags);
error = xfs_mount_log_sb(mp);
if (error) {
xfs_warn(mp, "failed to write sb changes");
return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment