mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-26 13:47:26 +00:00
xfs: check that the rtrmapbt maxlevels doesn't increase when growing fs
The size of filesystem transaction reservations depends on the maximum height (maxlevels) of the realtime btrees. Since we don't want a grow operation to increase the reservation size enough that we'll fail the minimum log size checks on the next mount, constrain growfs operations if they would cause an increase in those maxlevels. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
b3683c74bf
commit
59a57acbce
@ -22,6 +22,7 @@
|
||||
#include "xfs_ag_resv.h"
|
||||
#include "xfs_trace.h"
|
||||
#include "xfs_rtalloc.h"
|
||||
#include "xfs_rtrmap_btree.h"
|
||||
|
||||
/*
|
||||
* Write new AG headers to disk. Non-transactional, but need to be
|
||||
@ -114,6 +115,12 @@ xfs_growfs_data_private(
|
||||
xfs_buf_relse(bp);
|
||||
}
|
||||
|
||||
/* Make sure the new fs size won't cause problems with the log. */
|
||||
error = xfs_growfs_check_rtgeom(mp, nb, mp->m_sb.sb_rblocks,
|
||||
mp->m_sb.sb_rextsize);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
nb_div = nb;
|
||||
nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
|
||||
if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
|
||||
@ -221,7 +228,11 @@ xfs_growfs_data_private(
|
||||
error = xfs_fs_reserve_ag_blocks(mp);
|
||||
if (error == -ENOSPC)
|
||||
error = 0;
|
||||
|
||||
/* Compute new maxlevels for rt btrees. */
|
||||
xfs_rtrmapbt_compute_maxlevels(mp);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
out_trans_cancel:
|
||||
|
@ -989,9 +989,11 @@ xfs_growfs_rt_bmblock(
|
||||
goto out_free;
|
||||
|
||||
/*
|
||||
* Ensure the mount RT feature flag is now set.
|
||||
* Ensure the mount RT feature flag is now set, and compute new
|
||||
* maxlevels for rt btrees.
|
||||
*/
|
||||
mp->m_features |= XFS_FEAT_REALTIME;
|
||||
xfs_rtrmapbt_compute_maxlevels(mp);
|
||||
|
||||
kfree(nmp);
|
||||
return 0;
|
||||
@ -1159,29 +1161,37 @@ xfs_growfs_rtg(
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
xfs_growfs_check_rtgeom(
|
||||
const struct xfs_mount *mp,
|
||||
xfs_rfsblock_t dblocks,
|
||||
xfs_rfsblock_t rblocks,
|
||||
xfs_extlen_t rextsize)
|
||||
{
|
||||
xfs_extlen_t min_logfsbs;
|
||||
struct xfs_mount *nmp;
|
||||
int error = 0;
|
||||
|
||||
nmp = xfs_growfs_rt_alloc_fake_mount(mp, rblocks, rextsize);
|
||||
if (!nmp)
|
||||
return -ENOMEM;
|
||||
nmp->m_sb.sb_dblocks = dblocks;
|
||||
|
||||
xfs_rtrmapbt_compute_maxlevels(nmp);
|
||||
xfs_trans_resv_calc(nmp, M_RES(nmp));
|
||||
|
||||
/*
|
||||
* New summary size can't be more than half the size of the log. This
|
||||
* prevents us from getting a log overflow, since we'll log basically
|
||||
* the whole summary file at once.
|
||||
*/
|
||||
if (nmp->m_rsumblocks > (mp->m_sb.sb_logblocks >> 1))
|
||||
error = -EINVAL;
|
||||
min_logfsbs = min_t(xfs_extlen_t, xfs_log_calc_minimum_size(nmp),
|
||||
nmp->m_rsumblocks * 2);
|
||||
|
||||
kfree(nmp);
|
||||
return error;
|
||||
|
||||
if (min_logfsbs > mp->m_sb.sb_logblocks)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1300,7 +1310,8 @@ xfs_growfs_rt(
|
||||
goto out_unlock;
|
||||
|
||||
/* Make sure the new fs size won't cause problems with the log. */
|
||||
error = xfs_growfs_check_rtgeom(mp, in->newblocks, in->extsize);
|
||||
error = xfs_growfs_check_rtgeom(mp, mp->m_sb.sb_dblocks, in->newblocks,
|
||||
in->extsize);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
|
||||
|
@ -46,6 +46,8 @@ xfs_growfs_rt(
|
||||
xfs_growfs_rt_t *in); /* user supplied growfs struct */
|
||||
|
||||
int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
|
||||
int xfs_growfs_check_rtgeom(const struct xfs_mount *mp, xfs_rfsblock_t dblocks,
|
||||
xfs_rfsblock_t rblocks, xfs_agblock_t rextsize);
|
||||
#else
|
||||
# define xfs_growfs_rt(mp,in) (-ENOSYS)
|
||||
# define xfs_rtalloc_reinit_frextents(m) (0)
|
||||
@ -65,6 +67,14 @@ xfs_rtmount_init(
|
||||
# define xfs_rtunmount_inodes(m)
|
||||
# define xfs_rt_resv_free(mp) ((void)0)
|
||||
# define xfs_rt_resv_init(mp) (0)
|
||||
|
||||
static inline int
|
||||
xfs_growfs_check_rtgeom(const struct xfs_mount *mp,
|
||||
xfs_rfsblock_t dblocks, xfs_rfsblock_t rblocks,
|
||||
xfs_extlen_t rextsize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
#endif /* __XFS_RTALLOC_H__ */
|
||||
|
@ -5622,6 +5622,27 @@ DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_free_space);
|
||||
DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_critical);
|
||||
DEFINE_INODE_ERROR_EVENT(xfs_metafile_resv_init_error);
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
TRACE_EVENT(xfs_growfs_check_rtgeom,
|
||||
TP_PROTO(const struct xfs_mount *mp, unsigned int min_logfsbs),
|
||||
TP_ARGS(mp, min_logfsbs),
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(unsigned int, logblocks)
|
||||
__field(unsigned int, min_logfsbs)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->dev = mp->m_super->s_dev;
|
||||
__entry->logblocks = mp->m_sb.sb_logblocks;
|
||||
__entry->min_logfsbs = min_logfsbs;
|
||||
),
|
||||
TP_printk("dev %d:%d logblocks %u min_logfsbs %u",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->logblocks,
|
||||
__entry->min_logfsbs)
|
||||
);
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
#endif /* _TRACE_XFS_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
Loading…
Reference in New Issue
Block a user